Ajax History, iframe v.s. hash polling

Status
Niet open voor verdere reacties.

Glest

Gebruiker
Lid geworden
6 sep 2007
Berichten
688
Hoi allemaal,

Ik ben nu (voor het eerst) bezig met een puur Ajax applicatie (geen php backend). SEO is niet belangrijk voor het geval iemand daar over wil beginnen. Alles werkt eigenlijk, maar ik vraag me af of het niet beter kan.

De standaard methode tegenwoordig om de back/forward knoppen van je browser te laten werken met een Ajax applicatie, is het updaten van location.hash. In de meeste browsers zorgt dit voor een item in de geschiedenis lijst. Om dan vervolgens je Ajax applicatie aan te passen kun je elke x milliseconden controleren of de location.hash is gewijzigd. Niet erg efficiënt.

Maar bij IE moet het anders. Als je de location.hash wijzigt komt er géén item in de geschiedenis en kun je dus ook de back / forward knoppen niet gebruiken. Om dit te verhelpen kun je een verborgen iframe gebruiken en daar steeds de src van wijzigen. Stel je wilt bijvoorbeeld "index.html#state=1" in de geschiedenis hebben, dan verander je de src van het iframe in "hidden.html?state=1". hidden.html kan dan vervolgens dit script uitvoeren:
PHP:
if (parent)
{
  var query			 = window.location.search;
  var hash			 = query.replace(/[?&;]/g, "#");
  parent.location.hash		 = hash;
}

Hierdoor heb je in principe een werkende workaround. De hash van het parent window wordt geupdate, die wordt gepolled en je content wordt geupdate.

Maar, als je nou deze iframe hack in alle browser toepast en het script wat uitbreid zou je het hele pollen van de location.hash in principe achterwege kunnen laten. Stel je hebt een functie in je hoofd applicatie die de location.hash opvraagt.
PHP:
function process_hash()
{
  // get location.hash and update page
}

Dan kun je het script in de body/head van hidden.html uitbreiden naar dit:
PHP:
if (parent)
{
  var query			 = window.location.search;
  var hash			 = query.replace(/[?&;]/g, "#");
  parent.location.hash		 = hash;
  parent.process_hash();
}

Dan hoef je niet meer elke 100 milliseconden de hash te vergelijken. Maar het grote nadeel is dat bij elke status update er een nieuwe pagina geladen moet worden in het iframe. Iets wat nu alleen bij IE hoeft, en wie gebruikt IE nou.

Ik vraag me dus eigenlijk af wat jullie denken dat beter is. Elke 100 ms de location.hash opvragen en vergelijken of bij elke state verandering een pagina laden in een verborgen iframe? Het is een kleine pagina, maar met langzaam netwerk verkeer kan het toch lang duren.



/edit: En ik zie nu dat er dubbele items in de geschiedenis komen bij firefox. Logisch opzich, één keer voor de iframe reload en één keer voor de hash update. Maar negeer dat maar voorlopig, misschien dat ik daar nog iets op kan vinden.
 
Laatst bewerkt:
niemand een mening? :eek:

Nouja, persoonlijk denk ik niet dat het laden van een pagina in een iframe het waard is om van hash polling af te kunnen stappen. Het is nodig in IE, dus daar hoef je de hash niet te pollen maar voor normale browsers hou ik het maar bij een 100ms interval.
 
Ik weet dat dit een oude post is, maar voor mij is het een recent probleem. Het is me gelukt om in FF2+ de backbutton en bookmarking te fixen, alleen in IE lukt het maar niet. Nu zag ik je oplossing met het hidden iframe, maar ik snap hem niet :o

Iemand die het mij kan verduidelijken (adhv een voorbeeld)?

Gr. Spoook
 
Ik kan je wel de theorie uitleggen.

Normaal gesproken kun je de hash van je pagina veranderen. In de meeste browsers zorgt dit voor een item in de back/forward geschiedenis. Als je teruggaat in de geschiedenis wordt de hash weer veranderd. Die kun je elke 100 ms controleren op veranderingen en je pagina updaten.

Maar in IE7 en lager (dus niet IE8!) wordt er geen item toegevoegd aan de back/forward geschiedenis als de hash niet bestaat. Dus in plaats daarvan gebruiken we een iframe en we zetten de iframe.src naar een nieuwe locatie (iframe_hack.html?a=b&c=d). En in die pagina zet je een script wat de hash van zijn parent update en vervolgens roep je de functie aan (ook van zijn parent) die de hash controleert en de pagina update. Als je nu teruggaat in de geschiedenis wordt de pagina in het iframe teruggezet en wordt het script in die pagina ook opnieuw uitgevoerd.

Maar let erop dat je dit alleen in IE7 en lager doet, anders krijg je dubbele invoeringen in de back/forward geschiedenis.

Het script in de body van iframe_hack.html kan bijvoorbeeld dit zijn:
Code:
if (parent)
{
  var query             = window.location.search;
  var hash             = query.replace(/[?&;]/g, "#");
  parent.location.hash         = hash;
  parent.process_hash();
}
 
hey, een oude post. Nooit gezien.

Nu moet ik zeggen dat ik me nooit zo verdiept heb in de workarounds voor de history van has/ajax navigatie, maar om alleen voor IE een workaround te verzinnen is natuurlijk belachelijk. Zoals je zelf al zei, wie gebruikt er nou IE. Bovendien, IE8 had dit toch opgelost, en sinds (tenminste dat neem ik aan) de meeste mensen auto updaten naar een nieuwe versie van IE zou ik me er niet zoveel zorgen over maken.

Maargoed, ik zou dus lekker voor de 100ms gaan en niet moeilijk doen met een iframe.



:thumb:
 
Laatst bewerkt:
Tja, het is niet netjes, het gebruikt browser detectie en ondermijnt een van de voordelen van Ajax. Maar ondertussen is het wel de enige manier in IE7 en lager. Voorlopig is IE8 nog niet voorbij RC (toch?) en het verbaast mij steeds hoeveel mensen er nog op IE6 zitten :shocked:

Het is wel hoe ik voor het Ajax tijdperk HTTP requests maakte. Ik laadde een pagina met een script in een verborgen iframe (desnoods een iframe met een formulier erin voor post requests) en voila. Ajax is makkelijker en netter, maar het is voor mij redelijk vertrouwd
 
Ik heb het script al dat de hash vervangt en update voor FF3 ed. (zelf gemaakt):

alleen ik vraag me af welke browserdetectie methode ik moet gebruiken, want ik wil natuurlijk geen dubbele hash dingen ;)
 
ik zou zo iets gebruiken:
Code:
var iframe_hack = (navigator && navigator.appName && navigator.appName == "Microsoft Internet Explorer" && parseInt(navigator.appVersion.replace(/^.*?MSIE (\d).*$/, "$1")) <= 7);

Aangezien de major versie van IE niet duidelijk te vinden is heb je een regex nodig.
 
Laatst bewerkt:
Code:
var iframe_hack = (navigator && navigator.appName && navigator.appName == "Microsoft Internet Explorer" && parseInt(navigator.appVersion.replace(/^.*?MSIE (\d).*$/, "$1")) <= 7);

if(iframe_hack){
	alert('Jep dit is IE!');
}

Als ik dit gewoon tussen de <head> tags van een document zet, krijg ik 2x de alert te zien in IE7, dus ik ga ervan uit dat de code van if(iframe_hack){} 2x uitgevoerd wordt, hoe kan dit? (en hoe kan ik het verhelpen?)

Daarnaast, ik weet dat het lelijk is maar moet ik onderin m'n body maar planten:

Code:
if(iframe_hack){
   document.write("<iframe src=....></iframe>");
}

Of kan ik gewoon werken met innerHTML of createElement?
 
Laatst bewerkt:
createElement werkte gewoon bij mij (netste oplossing ook).

Maar die code hoort echt maar één keer uitgevoerd te worden. Kun je het hele <script> laten zien waar het in staat?

Mijn oplossing staat hier online overigens: http://weer.hml.nl (inderdaad, de gegevens van de afgelopen paar maanden missen, het gaat ook om de code ^^ )
Waarschijnlijk iets te veel code om echt iets aan te hebben maar wie weet.
 
Laatst bewerkt:
@Glest

Ik heb je historycode even opgehaald, heb je er problemen mee als ik stukken ga gebruiken voor een ajax shopping cart oplossing ?

Ik gebruik nu RSH (Really Sipmple History) en daar wilde ik al in gaan wijzigen omdat ik er niet tevreden mee ben maar met jouw trouwens nette code, als basis kan ik een meer op maat gemaakte history implementeren.

Alvast bedankt,

Joop.
 
Hey Joopbu,

Absoluut geen probleem, ben altijd blij als mijn code nog meer personen kan helpen dan alleen mijzelf :thumb:
 
ik zou zo iets gebruiken:
Code:
var iframe_hack = (navigator && navigator.appName && navigator.appName == "Microsoft Internet Explorer" && parseInt(navigator.appVersion.replace(/^.*?MSIE (\d).*$/, "$1")) <= 7);

Aangezien de major versie van IE niet duidelijk te vinden is heb je een regex nodig.

Om dit topic maar weer naar boven te halen:
Je zou IE7 (en eerder) kunnen herkennen door[JS]
<script type="text/javascript">
var is_before_ie8 = false;
</script>
<!--[if lt IE 8]>
<script type="text/javascript">
is_before_ie8 = true;
</script>
<![endif]-->[/JS] te doen, toch? Zou dat niet makkelijker zijn :confused:

Gr. Robin
 
Ja, dat zou het zijn als ik mijn code in HTML bestanden zou zetten. Maar voor de overzichtelijkheid staat alles in externe javascript bestanden. Het is op zich een goede oplossing maar het JS is ineens niet meer leesbaar als een deel ervan in het HTML bestand staat. Maar dat ben ik, als andere het geen probleem vinden kunnen ze inderdaad beter doen wat jij voorstelt.
 
Laatst bewerkt:
Status
Niet open voor verdere reacties.
Terug
Bovenaan Onderaan