Jeg har for nylig taget Ajax til mig, og baner mig vej med små skridt. Det hele virkede så nemt til at starte med, indtil jeg løb ind i problemer med danske specieltegn. Så ledte jeg med lys og lygte, for at se om andre havde de samme problemer, og der faldt jeg over Olebole der kommenterede et indlæg om emnet.
Det gik op for mig at man kun må trække rå data ud, og f.eks. ikke må have html kode med. Hvad gør man så hvis det er flere værdier der skal hives ud på én gang? Hvordan håndtere man dette?
Når man så har fået sine data ud og vil have dem placeret i f.eks en tabelcelle, hvad gør man så, når nu ikke man må bruge innerHTML. Så vidt jeg kunne forstå på Ole var innerHTML en dårlig løsning, og man skulle hellere bruge DOM. Men er innerHTML ikke en del af DOM? Samtlige guides jeg har fundet på nettet omkring emnet bruger nemlig innerHTML, ikke at det skulle gøre det mere rigtigt :o)
Nej, innerHTML er bestemt ikke DOM. Snarere det modsatte. Og dét at samtlige guides bruger innerHTML styrker kun Oles påstand om, at stort set samtlige guides er noget l*rt. =)
xfox> Brugerne roenving og olebole plejer at sige, at følgende 2 sider er skod (de bruger nok ikke ordet "skod", men hey..), da de indeholder fejl:
html.dk w3schools.com
Jeg ved ikke om du har lagt mærke til det, men der står også "No" under "W3C" (helt ud til højre i tabellen) ud for "innerHTML".. så noget har de fanget.. :-)
Aha, har nu fået slået fast at innerHTML ikke er DOM. Så mangler jeg bare at finde ud af hvordan jeg håndtere flere værdier i output'et. Hvis jeg nu henter 3 værdier fra en database, via Ajax, hvordan kan jeg så bruge dem hver for sig? Jeg har jo kun en responseText hvor de havner i....eller?
Jeg har engang læst/hørt/set/andet at det at bruge "eval" er no-no, fordi det skulle være krævende.. måske noget reference-halløj også.. men det kan de kloge hovedet nok svare på.. :-)
Ja, har hørt nogen sige, der er ulemper, nogle overforbruger det derimod. Personligt bruger jeg det kun sammen med JSOn, som vist ovenfor. Og jeg mener i øvrigt, det kun kan gøres med Eval().
kalp >> Du bør sætte dig ind i, hvad JSON er. JSON og XML kæmper ingenlunde om samme plads eller forsøger at udelukke hinanden, men kan forskellige ting og har hver deres fordele. Dog er JSON ofte at foretrække til brug i Ajax - og her kan du sende ligeså komplekse data tilbage til klienten, som du kan med XML ;o)
thesurfer >> Det er helt korrekt, at man bør begrænse brugen af eval til et absolut minimum. Eval er i virkeligheden en fantastisk funktion, der kan en utrolig bunke, men netop fordi den skal kunne så meget, bliver den ret langsom. Mange kodere bruger den til ting, hvor den ligeså godt kan undværes - og så bør den _absolut_ undværes - men den kan ikke undværes, når et XMLHttpRequest objekt returnerer en JSON-streng, der skal 'tilbage-serialiseres' til et JavaScript objekt.
xfox >> kik evt. i denne tråd, hvor jeg har forklaret lidt om brugen af JSON - og dermed også om at få mere komlekse data overført og indsat i siden: http://www.eksperten.dk/spm/817625
Til at hjælpe på forståelsen af JSON kan det måske være en idé at læse denne artikel om sammenhængen mellem arrays (ikke mindst de associative arrays) og objekter i java script: http://www.eksperten.dk/artikler/227
De store problemer med Ajax opstår, når man sætter event handlers på elementer. Problemerne opstår primært i IE, der har en 'ret særegen' garbage collection. Der opstår meget let en situation, hvor det indre af en funktion refererer til et DOMElement - som igen refererer til en funktion (eller reference til en sådan), indenfor den første funktions scope. Derved 'låses' funktions-scopet sammen med DOMElementet i en såkaldt cirkulær reference. Denne reference kan ikke umiddelbart brydes, når elementet nedlægges, men vil fortsætte med at beslaglægge plads i hukommelsen. Ikke engang når der navigeres til en anden side, bliver der frigivet hukommelse. Først når browserinstansen lukkes, frigives hukommelsen endelig.
Den slags memory leaks kan ved større applikationer meget let ende med at rive browseren på gulvet - og i bedste fald få applikationen til at blive ekstremt langsom!
Egentlig er problemet ikke knyttet til Ajax som sådan. Det bliver blot meget lettere synligt, når der ikke navigeres og der oprettes og nedlægges i hundredevis (og ofte tusindvis) af elementer ... så summer de enkelte, forholdsvis små leaks hurtigt op!
Forestil dig et forretnings- eller lagerstyrings system - eller noget andet, hvor man vedligeholder en database med mange felter. Her vil man ofte bruge en tabel, hvor rækker hele tiden oprettes og nedlægges - og måske endda gennem en hel dag. Det bliver lynhurtigt _rigtig_ mange rækker med mange celler i hver - og med tilhørende mouseover effekter og sikkert også noget onclick. That spells 'DEATH'! ... eller et iskoldt overblik ;o)
En anden ting er at udføre tingene i en hensigtsmæssig rækkefølge, når man koder DOM. Hvis du opretter et element med createElement og tilføjer en event handler, inden elementet er indsat i dokumentets DOM-træ, vil der også opstå en memory leak. I så tilfælde vil der nemlig blive oprettet et 'midlertidigt', lokalt script scope. Når elementet indsættes i dokumentet, oprettes det endelige script scope for det pågældende element, og det midlertidige burde nedlægges i hukommelsen. Det sidste sker bare ikke i IE med en memory leak til følge :o|
Derfor bør man altid først tilføje event handlers, efter et element er appended til et eller anden i dokumentets DOM-træ. Det kan medføre lidt ekstra kode, men det må man tage med. Af performance hensyn sætter man helst ikke elementer direkte ind i dokumentet, hvis der er tale om mange elementer - f.eks. at skifte 50 rækker i en tabel med nye data. I stedet opretter man et tbody-element i hukommelsen, som man appender alle de nye rækker til. Når alle rækker er indsat, bruges replaceChild til at bytte det eksisterende tbody-element ud med det nye ... og man skal derefter huske at fjerne/null'e alle event handlers på elementer i det fjernede tbody-element og null'e disse. Først derefter går man alle rækker igennem i en ny løkke og tildeler event handlers.
Hermed fik vi lige kradset en anelse i Ajax' overflade. Det er absolut ikke en teknik, der er lige til kaste sig ud i. Først, når du er i stand til at skrive rigtig komplekse HTML, JavaScript, CSS, DOM applikationer - og har opnået meget stor erfaring med de forskellige browseres mere eller mindre udokumenterede særheder - kan du så småt begynde at kaste dig ud i at udforske Ajax :)
Du kan såmænd sagtens bruge innerHTML til indsættelse af data i dokumentet. Loftet falder ikke ned over dig, og du får ikke blodfyldte bylder omkring ringmusklen af det. Er man meget påpasselig, kommer man endda heller ikke til at overskrive event handlers eller referencer. Derfor er der mange, der argumenterer for brugen af innerHTML og finder det religiøst hysteri at argumentere mod.
Selvom man kan være nok så påpasselig med den kode, man sidder og koder ind i, kan man ikke forudse, hvordan koden evt. skal udvides på et senere tidspunkt. Overfor disse udvidelser ken man ikke være påpasselig - og brugen af innerHTML kan derfor meget vel begrænse mulighederne for evt. senere udvidelser.
Desuden er det ikke muligt for mig at arbejde med den form for 'fleksibilitet' overfor standarderne. Der er fortrinlige muligheder for manipulation af elementer med DOM og dermed igen grund til at bruge invalid kode. Hvis det er okay at bruge invalid kode som innerHTML, hvor meget er det så nødvendigt at overholde andre dele af standarderne - og hvorfor? Hvormange procent invalid kode kan jeg tillade mig at bruge?
Hvorfor dog besvære sig med den slags komplicerede overvejelser, når der findes fremragende, valide alternativer til invalid kode? ;o)
Der skulle sæ'fø'li' stå 'ingen grund': "Der er fortrinlige muligheder for manipulation af elementer med DOM og dermed ingen grund til at bruge invalid kode." =)
Det er kun logisk for mig, at vælge XML da det til dagligt er det jeg arbejder med. Arbejder stortset kun med SOA og alt kommunikation mellem systemerne er via. XML.
Jeg siger ikke, at JSON er skidt:) og jeg kommer sikkert også til at prøve det af på et tidspunkt når den rigtige opgave lander på mit bord:)
Ole>> Måske lidt off-topic, og så måske alligevel ikke. Synes det passer godt til din beskrivelse af DOM i hvert fald.
documentFragment-objektet beskrives som en "letvægts"-udgave af document-objektet og og virker da derfor langt mere hensigtsmæssig at bruge til midlertidig opbevaring af elementer/noder, inden de placeres synligt i dokumentet. Hvornår vil det så være bedst at bruge document.documentFragment fremfor blot document? Jeg synes ikke, jeg kan finde så mange gode eksempler af det på nettet - for det meste er det bare variationer af den samme W3C-forklaring.
Jeg så bl.a., at du brugte documentFragment i en af dine artikler og det skærpede jo lidt min interesse, da jeg aldrig selv rigtig har benyttet det.
Et dokumentFragment er en lidt pudsigt, 'pseudoagtig' node. Du kan bruge den til at indsætte andre noder i. Når de ønskede elementer er tilføjet, kan fragmentet indsættes et sted i DOM-træet - hvorefter fragmentet så at sige 'forsvinder'.
DokumentFragmentet er ikke til at finde i DOM-træet, og undersøger man fragmentets indhold efter dets indsættelse i træet, viser det sig at være tomt! Dets 'børn' er blot blevet overført til dokumentets DOM-træ, mens fragmentet selv bliver liggende i hukommelsen.
Prøv denne lille kode (Bemærk, at et documentFrament's nodeType er 11 - mens et alm. DOMElement har nodeTypen 1):
<script type="text/JavaScript"> function foo() { var oDocFrag = document.createDocumentFragment(); var oDiv = document.createElement("div"); oDocFrag.appendChild(oDiv); oDiv.appendChild( document.createTextNode("Blabla A") ); document.getElementById("gnu").appendChild(oDocFrag); alert("NodeType af divets parentNode: " + oDiv.parentNode.nodeType);
alert("Antal childNodes i fragmentet efter indsættelse: " + oDocFrag.childNodes.length); var oDivB = document.createElement("div"); oDocFrag.appendChild(oDivB); oDivB.appendChild( document.createTextNode("Blabla B") ); document.getElementById("gnu").appendChild(oDocFrag); } </script>
<p><button onclick="foo()">TEST</button></p>
<div id="gnu"></div>
Man kan indsætte tabelrækker i et tbody-element og efterfølgende udskifte en tabels tbody med den ny tbody ... og tømme/rense den gamle tbody (og dermed frigøre hukommelse).
I stedet kan man indsætte tabelrækker i et documentFragment. Så vil man først tømme/rense en tabels bestående tbody og efterfølgende appende fragmentet til tbody-elementet.
Umiddelbart tror jeg ikke, der er den store forskel på de to metoder - men den antagelse bygger alene på 'tro og religion'. Jeg har endnu ikke testet og sammenlignet performance, m.m, men det vil jeg nok gøre meget snart ;o)
Meget interessanter informationer. Det gav lidt at både tænke og læse over. Uden at være den store haj til hverken DOM, AJAX eller JSON prøvede jeg at lave koden om så den passede til min HTML med Div'er. I stedet for at holde øje med hvilket nummer TD man var kommet til ved indsættelse af data, lavede jeg et almindelig plain reference til ID'et på mine div'er:
var d=document; function gE(id){return d.getElementById(id)}; function gA(o,t){return o.getElementsByTagName(t)};
function myCallBack(oHttp) { eval("var oResp = " + oHttp.responseText);
var aRows = oResp.rows; for (var i=0,j=aRows.length; i<j; i++) { gE("info-overskrift").childNodes[0].nodeValue = aRows[i].aktivitet; gE("content").childNodes[0].nodeValue = aRows[i].beskrivelse; gE("link").childNodes[0].nodeValue = aRows[i].link;
} }
Det virker også fint, og data bliver indsat. Desværre er den ikke helt glad for æøå. Syntes ikke det hjælper, om jeg bruger utf-8 eller iso-8859-1 i charset, uden at kende forskellen. Er jeg helt på vildspor?
I dokumentet, du udskriver JSON med, skriver du aller øverst en HTTP-header: header("Content-Type: application/json; charset=utf-8");
- ligesom du skal bruge en utf-8 meta i dit HTML-dokument.
Desuden skal du sørge for at gemme alle dokumenter som utf-8. Du kan evt. åbne dem i Notepad og sørge for, de bliver gemt korrekt (encoding håndteres nederst i Save As dialogen i Notepad).
Henter du data fra en database, skal du f.eks. i phpMyAdmin sørge for den korrekte kollation på dine tabeller (utf-8).
Husk at sætte flueben i 'Verbose Output'. Så vil du kunne aflæse det tegnsæt, serveren sender dokumenterne med. Er det iso-8859-1, må du omdøbe filen til '*.php', hvis det nu hedder '*.html'. Derefter skriver du endnu en HTTP-header ... denne gang i toppen af HTML-dokumentet:
<?php header("Content-Type: text/html; charset=utf-8"); ?> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> ... osv ... osv ...
roenving >> Det er helt korrekt. Det er af hensyn til brug af sære feltnavne, som evt. kan kollidere med JavaScripts vokabularium. Det burde ikke genere her, men det er da en vigtig detalje at tage med ;o)
Det er som om at det ikke hjælper. Jeg har sat alle headers, og ændret min database kollation fra latin til utf8_unicode_ci. Desuden melder validatoren også tilbage at det er utf-8, dog siger den at det tekst jeg har på siden, hvoriblandt der er æøå, ikke kan valideres da det ikke er korrekt utf8 format..?
Jeg kan ikke komme tættere på, hvad du laver af fejl uden at se et link - men det er helt sikkert, du laver fejl et eller andet sted. Er du f.eks. helt sikker på, dine dokumenter er gemt som Unicode (utf-8)?
Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.