[Ajax] onreadystatechange wechseln?

Dieses Thema im Forum "Webentwicklung" wurde erstellt von Skull & Bones, 28. April 2012 .

Schlagworte:
Status des Themas:
Es sind keine weiteren Antworten möglich.
  1. 28. April 2012
    onreadystatechange wechseln?

    Hallo!
    Vorweg, ich habe wenig bis keine Ahnung von Javascript/AJAX, meine Stärken liegen in anderen Bereichen. Aber ich habe schon Google und die Forensuche bemüht und keine Antwort auf mein Problem gefunden.

    Ich habe ein Skript mit PHP geschrieben, die verschiedene Seiten auswertet. Damit das ganze etwas dynamischer ist, habe ich mir diese paar Zeilen AJAX geschnappt, damit man sieht ob die Seite noch lädt und man auch schon vorher Ergebnisse sieht.
    Soweit funktioniert der Code auch... Auf der Php-Seite gibts ein Suchfenster, das entsprechend loadContent() aufruft:

    Spoiler
    HTML:
    <div id="Search" class="search">
     <form onsubmit="return loadContent();" action="">
     <p>Spielname</p>
     <p><input name="crawly" id= "crawly" type="text" 
     size="30" maxlength="30"/></p>
     <p><input type="submit" value="submit" /></p>
     </form>
     </div>
     </div>
     
     <div id="Wrap"><div id="Container"><div id="Center">
     <div id="Content">
     </div>
     </div>
     </div>
     <div class="clear">&nbsp;</div>
     </div>

    Das ist der eigentliche AJAX-Teil, der auch arbeitet:

    Spoiler
    PHP:
    var  xmlHttpObject  false ;

    if (
    typeof XMLHttpRequest  !=  'undefined'
    {
        
    xmlHttpObject  = new  XMLHttpRequest ();
    }

    if (!
    xmlHttpObject
    {
        try 
        {
            
    xmlHttpObject  = new  ActiveXObject ( "Msxml2.XMLHTTP" );
        }
        catch(
    e
        {
            try 
            {
                
    xmlHttpObject  = new  ActiveXObject ( "Microsoft.XMLHTTP" );
            }
            catch(
    e
            {
                
    xmlHttpObject  null ;
            }
        }
    }

    function 
    loadContent ()
    {    
        var 
    crawl = encodeURIComponent ( document . getElementById ( "crawly" ). value );
        
    xmlHttpObject . open ( 'get' , 'crawl.php?crawl=' + crawl );
        
    xmlHttpObject . onreadystatechange  handleContent ;
        
    xmlHttpObject . send ( null );
        return 
    false ;
    }

    function 
    handleContent ()
    {
        if (
    xmlHttpObject . readyState  ==  1 )
        {
            
    document . getElementById ( 'Content' ). innerHTML  '<img src="ajax-loader.gif" alt="loading" />' ;
        }

        if (
    xmlHttpObject . readyState  ==  3 )
        {
            
    document . getElementById ( 'Content' ). innerHTML  xmlHttpObject . responseText  '<div class="Loading"><img src="ajax-loader.gif" alt="loading" /></div>' ;
        }
        
        if (
    xmlHttpObject . readyState  ==  4 )
        {
            
    document . getElementById ( 'Content' ). innerHTML  xmlHttpObject . responseText ;
        }
    }

    }

    Jetzt habe ich analog dazu folgendes eingefügt:
    Spoiler
    PHP:
    function  loadVGC ()
    {
        var 
    vgc = encodeURIComponent ( document . getElementById ( "vgch" ). value );
        
    xmlHttpObject . open ( 'get' , 'crawl.php?vgc=' + vgc );
        
    xmlHttpObject . onreadystatechange  handleVGC ;
        
    xmlHttpObject . send ( null );
        return 
    false ;
    }

    function 
    handleVGC ()
    {
        if (
    xmlHttpObject . readyState  ==  1 )
        {
            
    document . getElementById ( 'VGC' ). innerHTML  '<img src="ajax-loader.gif" alt="loading" />' ;
        }

        if (
    xmlHttpObject . readyState  ==  3 )
        {
            
    document . getElementById ( 'VGC' ). innerHTML  xmlHttpObject . responseText  '<div class="Loading"><img src="ajax-loader.gif" alt="loading" /></div>' ;
        }
        
        if (
    xmlHttpObject . readyState  ==  4 )
        {
            
    document . getElementById ( 'VG' ). innerHTML  xmlHttpObject . responseText ;
        }


    Der Ablauf auf der Seite ist jetzt folgender:
    Zuerst wird die erste Anfrage erzeugt, in deren Rückgabe wird dann das zweite Suchfeld erzeugt (analog zum ersten und entsprechend angepasst mit VGC-id-div und vgch-Textfeld). Im inneren Suchfeld soll man jetzt den Inhalt des VGC-divs verändern um das Suchwort für bestimmte Unterseiten zu ändern, genau wie vorher. Das eigentliche Problem ist jetzt, dass nur der Ladebalken kommt. Beim Testen habe ich herausgefunden, dass auch, wenn im zweiten Suchfeld
    HTML:
    <form onsubmit="return loadVGC();" action="">
    steht, trotzdem der handleContent()-Teil genutzt wird, also vermutlich loadVGC ignoriert/blockiert wird. Woran liegt das bzw wie behebe ich das?
     
  2. 28. April 2012
    AW: onreadystatechange wechseln?

    Code:
    function curry(fn) {
     var slice = Array.prototype.slice,
     args = slice.call(arguments, 1);
     
     return function() {
     args = args.concat(slice.call(arguments));
     return fn.apply(fn, args);
     };
    }
    
    function request(url, fn) {
     var xhr = new XMLHttpRequest;
     xhr.open('GET', url, true);
     xhr.onreadystatechange = curry(fn, xhr);
     xhr.send();
    }
    
    request('dieses.php', function(req) {
     if (req.readyState === 4) {
     // mach was...
     }
    }); 
    
    request('jenes.php', function(req) {
     if (req.readyState === 4) {
     // mach was anderes
     }
    });
    im "schnell antworten" editor entstanden. ggf. bugs vorhanden, aber das konzept sollte klar sein.
     
    1 Person gefällt das.
  3. 30. April 2012
    Zuletzt bearbeitet: 2. Mai 2012
    AW: onreadystatechange wechseln?

    aha okay, also völlig anderer ansatz. ich kanns leider noch nicht wieder testen und weiss auch noch nicht ob ich die beziehungen untereinander auf die schnelle verstanden habe... aber warum geht mein ansatz nicht? was ist das problem? will ja auch was dazu lernen.


    EDIT:

    okay, also statt loadContent nutze ich jetzt function request(url, fn) so wie ich das verstehe, aber was ist fn? ich nehme ja nicht an, dass ich in den onSubmit-Teil reinschreiben muss :
    Code:
    request('jenes.php', function(req) {
     if (req.readyState === 4) {
     // mach was anderes
     }
    })
    innerhalb des requests bekommt curry auch noch als weiteren parameter das XMLHttpRequest mitgeliefert, nutzt es aber nicht, nehme aber an dass das auch nicht nötig ist und einer der von dir angesprochenen bugs durch on-the-fly-code. und wie man dann von curry zu den einzelnen requests (jenes.php etc.) unten kommt verstehe ich auch nicht.
     
  4. 3. Mai 2012
    Zuletzt bearbeitet: 3. Mai 2012
    AW: onreadystatechange wechseln?

    ok, scheinbar hast du nicht ganz verstanden was genau im code passiert - sorry, ich hätte das gnaze vielleicht ein wenig offensichtlicher gestalten sollen ... das hat man nun davon wenn man einfach zuviel mit javascript arbeitet, denn dann stellt sich dein hirn auf die ganzen wtf's ein und, ja man glaubt es kaum, die ganzen sachen ergeben perfekt sinn

    hier nun eine kommentierte version des codes:

    Code:
    /**
     * diese funktion erzeugt eine neue funktion
     * die die übergebenen parameter an die übergebene funktion
     * bindet.
     *
     * diese art von closure-generator nennt man "curring"
     * 
     * @param Function fn die funktion
     * @param Object ... weitere parameter die an die funktion gebunden werden
     * @return Function die erstellte funktion
     */
    function curry(fn) {
     var slice = Array.prototype.slice, // referenz auf die array.slice methode
     args = slice.call(arguments, 1); // alle angebenen parameter bis auf den ersten
     
     // Array.prototype.slice schneidet einen array an
     // der angegebenen stelle ab und gibt den rest zurück.
     
     // in `args` befinden sich nun alle parameter bis auf den ersten
     // der hier ja benannt wurde mit `fn` (den brauchen wir nicht zweimal)
     
     // dazu verwenden wir das objekt `arguments`
     // in welchem sich alle parameter befinden, egal ob die
     // funktion sie erwarten (wie z.b. `fn`) oder eben nicht.
     
     // hier erzeugen wir eine NEUE funktion,
     // welche beim aufruf die übergebene funktion `fn`
     // ausführt.
     return function() {
     // selbes spiel wie zu anfang.
     // achtung: `arguments` wird nun von DIESER funktion erzeugt!
     
     // wir kombinieren nun die parameter der funktion `curry`
     // und die parameter dieser funktion zu einem array
     // und übergeben dieses an unsere funktion `fn`
     args = args.concat(slice.call(arguments));
     
     // wir rufen die function mittels .apply auf um
     // unsere eigens erstellten parameter als array
     // zu übergeben
     return fn.apply(fn, args);
     };
    }
    
    /**
     * xml-http-request
     *
     * @param String url wohin die anfrage soll
     * @param Function fn eine funktion die als `onreadystatechange` callback dienen soll
     */
    function request(url, fn) {
     // instanz erzeugen
     var xhr = new XMLHttpRequest;
     
     // öffnen als GET und async
     xhr.open('GET', url, true);
     
     // hier der wichtige teil!
     // wir binden das objekt `xhr` an die funktion `fn`
     // d.h. wenn die funktion nun aufgerufen wird ist das objekt `xhr`
     // IMMER der erste parameter, egal ob weitere parameter an die funktion
     // übergeben werden -> `xhr` ist immer an erster stelle!
     xhr.onreadystatechange = curry(fn, xhr);
     
     // anfrage absenden
     xhr.send();
    }
    
    // und hier die beispiele.
    
    // wie du sehen kannst ist das objekt `req`
    // angegeben, was dem `xhr` objekt in der funktion `request`
    // entspricht.
    request('dieses.php', function(req) {
     if (req.readyState === 4) {
     // mach was...
     }
    }); 
    
    // vielleicht macht es so mehr sinn:
    
    request('dieses.php', function(xhr) {
     if (xhr.readyState === 4) {
     // mach was...
     }
    }); 
    rechtschreibfehler darfst du behalten

    ps: kopier den code in deinen editor mit syntax-highlight, dann liest es sich angenehmer.

    links:
    John Resig - Partial Application in JavaScript

    nochmal wegen curry:
    Code:
    function show(val) {
     alert(val);
    } 
    
    var hello = curry(show, "hello");
    hello(); // gibt "hello" aus
    
    var world = curry(show, "world");
    world(); // gibt "world" aus
     
  5. 3. Mai 2012
    AW: onreadystatechange wechseln?

    irgendwie ist das alles etwas frustrierend.
    ich hab mir jetzt mal 2 tuts und einführungen zu currying durchgelesen, jetzt verstehe ich zumindest den sinn dahinter. allerdings sehe ich trotz deiner kommentare einfach nicht das grosse ganze im code, gerade auch weil das so verschachtelt ist. z.b. sehe ich nicht, wozu ich mehr als 1 oder im zweifelsfall 2 argumente zusätzlich übergeben sollte. wozu brauche ich hier überhaupt currying? was habe ich hier von einer partiell ausgewerteten funktion? im prinzip will ich nur sagen "nimm den wert aus id xy, häng ihn an die url (z.B. abc.php?a=b) und gib die antwort im entsprechenden div aus". Ich habe keine ahnung woher ich ne funktion fn bekomme (oder wozu ich die brauche), wie ich von aussen an das xmlhttprequest komme und wie ich das ganze jetzt überhaupt im onSubmit-teil eines <form>-felds nutzen soll.
    ausser curry sehe ich keine funktion, die nur ein element im aufruf braucht, curry selbst wird aber erst in request aufgerufen und darin ist auch das xmlhttprequest enthalten, allerdings brauche ich dafür schon eine funktion als parameter.
    weniger relevant, aber doch fürs verständnis wichtiger: läuft das ganze dann über mehrere instanzen von xmlhttprequests oder immer nur über das eine, das im onreadystate angepasst wird?


    TL;DR
    HÄÄ? geht das ganze nicht zur not auch einfach ohne currying? das scheint mir komplizierter als nötig, oder ist das echt der einzige weg? es muss nicht elegant sein, nur funktional. als funktional hätte ich meine lösung gesehen, aber wie gesagt, irgendwie will die nicht. (kennst du den grund ...?)
     
  6. 3. Mai 2012
    AW: onreadystatechange wechseln?

    mmn. ist currying ein sehr wichtiger bestandteil, vorallem bei der verwendung von callbacks.

    klar gehts ohne, aber warum sollte man das tun?

    mit meinem beispiel hast du nun eine simple funktion für deine ajax-anfrage mit callback-parameter ohne globale abhänigkeiten.

    Code:
    function loadContent()
    { 
     var crawl=encodeURIComponent(document.getElementById("crawly").value);
     request('crawl.php?crawl=' + crawl, handleContent); 
     return false;
    } 
    
    function handleContent(xhr)
    {
     if (xhr.readyState == 1)
     {
     document.getElementById('Content').innerHTML = '<img src="ajax-loader.gif" alt="loading" />';
     }
    
     if (xhr.readyState == 3)
     {
     document.getElementById('Content').innerHTML = xmlHttpObject.responseText + '<div class="Loading"><img src="ajax-loader.gif" alt="loading" /></div>';
     }
     
     if (xhr.readyState == 4)
     {
     document.getElementById('Content').innerHTML = xmlHttpObject.responseText;
     }
    } 
    
    usw...
     
  7. 3. Mai 2012
    AW: onreadystatechange wechseln?

    soweit sieht es ja aus wie mein code der nicht funktioniert (nur durch currying doppelt so lang), wenn ich eine zweite handleContent-funktion nutzen will. du gehst der frage, warum das bei mir nicht so einfach geht ja anscheinend aus dem weg... natürlich bist du nicht mein persönlicher debugger, aber falls du es weisst, wäre es nett wenn du es mir sagen würdest.

    habe jetzt sogar noch einen (für mich) recht eigenartigen bug gefunden:

    wenn ich xmlHttpObject.onreadystatechange = handleContent () ; statt xmlHttpObject.onreadystatechange = handleContent; benutze, dann kommt er nur bis zu readyState 1 und hängt dort. ohne klammern funktioniert alles wie erwartet. wenn ich jetzt xmlHttpObject.onreadystatechange = handleVGC; einbaue und nutze, wird bis zu diesem teil alles genommen, sprich xmlHttpObject.open('get','crawl.php?vgc='+vgc); wird noch aufgerufen, allerdings, und das verwirrt mich nach wie vor, kommt danach der readyState 1 von Content und da bleibt er hängen. die seite liefert aber auf jeden fall eine rückgabe, d.h. selbst wenn er den content-teil nutzt, dann müsste er die daten ausgeben, nur halt im falschen div. was ist da los??

    EDIT:

    dazu ist noch zu sagen, in jedem fall wird zuerst einmal der handleContent-Teil genutzt, in der folge wird dann das div in dem vgc steht, gesendet wird und ausgegeben wird erst erzeugt.
     
  8. 4. Mai 2012
    AW: onreadystatechange wechseln?

    JavaScript - Grundlagen

    bitte durchlesen
     
  9. 8. Mai 2012
    AW: onreadystatechange wechseln?

    ist echt ne gute seite, danke. hat bei meinem problem aber leider auch nicht direkt weitergeholfen
    wichtiger war dann doch die frage
    anscheinend kann man den onreadystatechange-teil nicht überschreiben ohne abort. ich hab mich jetzt für ein einzelnes request entschieden (nicht getestet, aber ich nehme einfach mal an dass mehrere parallel laufen können) und entsprechend so umgesetzt:

    PHP:
    xhRequest  false ;
     
    function 
    createXmlHttpRequest () 
    {
        try 
        {
            return new 
    XMLHttpRequest (); 
        } 
        catch(
    e
        {
            try 
            {
                return new 
    ActiveXObject ( "Msxml2.XMLHTTP" ); 
            } 
            catch (
    e
            {
                try 
                { 
                    return new 
    ActiveXObject ( "Microsoft.XMLHTTP" );
                } 
                catch (
    e
                {
                    return 
    null ;
                }
            }
        }
    }

    function 
    abortCreate () 
    {
        if(
    xhRequest )
        {
            
    xhRequest . abort ();
            
    xhRequest  false ;
        }
        if(!
    xhRequest )
        {
            
    xhRequest  createXmlHttpRequest ();
        }
    }
     
    function 
    loadContent ()
    {    
        
    abortCreate ();
        
    //blabla
        
    xhRequest . onreadystatechange  handleContent ;
        
    xhRequest . send ( null );
        return 
    false ;
    }

    function 
    loadVGC ()
    {
        
    abortCreate ();
        
    // blabla
        
    xhRequest . onreadystatechange  handleVGC ;
        
    xhRequest . send ( null );
        return 
    false ;
    }
    läuft jetzt auch alles so wie erwartet. hab auch gleich noch gelernt, dass es am sinnvollsten ist, das ganze erst am ende einzubinden. in meinem fall zwar noch egal, aber man weiss ja nie. übrigens bringt der php-codeblock hier im forum wenigstens etwas highlighting in javascript.

    von meiner seite aus ist das problem geklärt, daher mache ich hier mal zu. mit currying beschäftige ich mich aber auf jeden fall auch noch mal wenn ich das hier fertig habe

    Danke!
     
  10. Video Script

    Videos zum Themenbereich

    * gefundene Videos auf YouTube, anhand der Überschrift.