AJAX
Børre Stenseth
Moduler>AJAX>Generelt>Kodestrategier

Kodestrategier

Hva
AJAX-koding på klienten

Når vi skal lage ikke-trivielle AJAX-løsninger må vi planlegge programmeringsarbeidet. Det kan fort bli mye Javascriptkode og det kan fort bli mye gjentagelser.

Det er i hvertfall to valgsituasjoner vi må ta stilling til:

  • Vi må ta stilling til om vi skal kode alt fra bunnen av eller om vi skal bruke et bibliotek. Dersom vi har et overkommelig problem og vi bestemmer oss for å kode fra bunnen av, så bør vi likevel planlegge koden.
  • Vi må ta stilling til hva slags dataformat vi skal bruke på de dataene vi henter og sender med i en request. Skal vi bruke tekst (myRequest.responseText) eller DOM (myRequest.responseXML) på klientsiden, og hvordan skal vi pakke data i text-formatet.

La oss ta utgangspunkt i det enkle tilfellet at vi bruker POST og at vi tolker svaret på en henvendelse som text, dvs. text som er formatert som XHTML fra tjeneren. Videre at denne teksten i sin helhet skal plasseres som innhold i en bestemt tag, merket med id, på siden. Dette er trolig den situasjonen som er mest vanlig i relativt enkle anvendelser. Koden for å handtere denne situasjonen er i sin enkle form slik:

var myRequest;
function startXMLHttpRequest(theUrl)
{
    if (window.XMLHttpRequest)
        myRequest = new XMLHttpRequest();
    else if (window.ActiveXObject)
    {
        try { myRequest = new ActiveXObject("Msxml2.XMLHTTP");
        }
        catch(e) {
            try {myRequest= new ActiveXObject("Microsoft.XMLHTTP");
            }
            catch(e) {myRequest=null;}
        }
    }
    else
        myRequest=null;
    if (myRequest) {
      myRequest.onreadystatechange = processRequestChange;
      params="<something we read form the page>";
      theRequest.open('POST',theUrl,true);
      theRequest.setRequestHeader("Content-type", 
                                  "application/x-www-form-urlencoded");
      theRequest.setRequestHeader("Content-length", params.length);
      theRequest.setRequestHeader("Connection", "close");
      theRequest.send(params);
    }
    else{
        alert("Nettleseren henger ikke med");
    }
}
function processRequestChange()
{
    // if the request is complete and successfull
    if (myRequest.readyState == 4) {
        if ((myRequest.status == 200) || (myRequest.status == 304))
            document.getElementById('resultat').innerHTML=
                myRequest.responseText;
        else
            alert("Problem med tilgang til data:\n" + myRequest.statusText);
    }
}

Koderasjonalisering

Vi merker oss at vi trenger en global variabel, myRequest, for å huske hvilken henvendelse som er "utestående". Vi ser dessuten at dersom vi har en løsning med mange henvendelser, så må vi for sikkerhets skyld huske mange henvendelser eller vi må sørge for at vi bare har en utestående om gangen.

Vi ser dessuten at dersom vi har mange mulige henvendelser så blir mye av koden ren gjentagelse: Vi skal opprette en forespørsel, vi skal sende den og vi skal ta i mot og plassere svaret. Det eneste som skiller en situasjon fra en annen er at vi har forskjellige adresser å plassere resultatet i, at vi har forskjellige parametere og kansje at vi har forskjellige URL'er.

Vi kan løse opp i denne situasjonen med å bruke de mulighetene Javascript gir oss for å kople en anonym funksjon til et request-objekt som onreadystatechange. Koden nedenfor gir oss et rammeverk, eller om du vil et lite bibliotek, som gjør at vi kan rasjonalisere koden kraftig.

function establishRequest()
{
    var theRequest=null;
    if (window.XMLHttpRequest)
        theRequest = new XMLHttpRequest();
    else if (window.ActiveXObject)
    {
        try { theRequest = new ActiveXObject("Msxml2.XMLHTTP");
        }
        catch(e) {
            try {theRequest= new ActiveXObject("Microsoft.XMLHTTP");
            }
            catch(e) {theRequest=null;}
        }
    }
    else
        theRequest=null;
    return theRequest;
}
function postRequest(theRequest,params,targetId,theUrl)
{
    theRequest.onreadystatechange =
        function( ) {
                    processRequestChange(theRequest,targetId);
        };
    theRequest.open("POST", theUrl,true);
    theRequest.setRequestHeader("Content-type", 
                                "application/x-www-form-urlencoded");
    theRequest.setRequestHeader("Content-length", params.length);
    theRequest.setRequestHeader("Connection", "close");
    theRequest.send(params);
}
function processRequestChange( aRequest,aTarget )
{
    if (aRequest.readyState == 4) {
        if ((aRequest.status == 200) || (aRequest.status == 304))
            document.getElementById(aTarget).innerHTML=
                aRequest.responseText;
        else
            alert("Problem med tilgang til data:\n" + aRequest.statusText);
    }
}

Ved hjelp av disse funksjonene kan et par AJAX-henvendelser fra siden vår kode se slik ut:

function startMenuRequest()
{
    var myRequest=establishRequest();
    if (myRequest) {
        postRequest(myRequest,
                   'theJob=country-list','leftmenu','../myscript.py');
    }
    else{
        alert("Nettleseren henger ikke med");
    }
}
function startResultHeaderRequest(ligaId)
{
    var myRequest=establishRequest();
    if(myRequest){
        postRequest(myRequest,
               'theJob=result-header&ligaId='+ligaId,
               'resultheader',
               '../myscript.py');
    }
    else{
        alert("Nettleseren henger ikke med");
    }
}

Dersom vi har behov for å sjekke data i en form eller hva det måtte være, kan vi gjøre dette i vår funksjon før vi setter opp en forespørsel. F.eks. slik:

function startMenuRequest(form)
{
    // pick up and control data from the form
    if (<something wrong or missing>)
    {
      <perform the proper alert or errormarking>
      return;
    }
    // proceed with the requst
    var myRequest=establishRequest();
    if (myRequest) {
        postRequest(myRequest,'theJob=country-list','leftmenu','../myscript.py');
    }
    else{
        alert("Nettleseren henger ikke med");
    }
}

Biblioteker

Selv om det vi har foreslått ovenfor kan være et nyttig knippe funksjoner for å effektivisere koding av enkle eksempler er det ikke et bibliotek som er generelt nok til å handtere og feilsikre mer komplekse situasjoner. Ikke uventet har den økte bruken av AJAX ført til at det dukker opp en rekke biblioteker av uilkt omfang som skal hjelpe oss å skrive rask og sikker AJAX-kode på klientsiden.

To interessante AJAX-biblioteker er prototype [1] og jQuery [2] . Det siste ser ut til å være det som er rikest. Du finner bruk av begge på de neste modulene.

Referanser
  1. prototype Javascript bibliotekprototypejs.orgwww.prototypejs.org/14-03-2010
  1. jQuery Javascript bibliotekjqueryjquery.com/04-07-2010
  1. AJAX-ressurserajax projectswww.ajaxprojects.com/14-03-2010
  1. mochikit Javascript bibliotekmochikitmochikit.com/14-03-2010
Vedlikehold

B.Stenseth, november 2006

(Velkommen) Moduler>AJAX>Generelt>Kodestrategier (Prototype)