johny7: jQuery: komisches Problem mit ajaxStop()

Moin allerseits,

ich habe in einer Funktion folgende Abfrage:

  
$('.pane').click(function(){  
	var pane = $(this).attr('ID');  
	alert(pane);  
	$('#'+pane).load('newfile.html');  
	$('#'+pane).ajaxStop(function () { alert('nach AJAX' + pane); });  
});  

Der HTML-Aufbau sieht folgendermaßen aus:

  
<div class="pane" id="pane1"></div>  
<div class="pane" id="pane2"></div>  
<div class="pane" id="pane3"></div>  
<div class="pane" id="pane4"></div>  

Bei jedem Klick auf den div-Tag wird der Inhalt neu geladen. Jetzt zeigt die Ausgabe beim ersten Mal erwartungsgemäß die ID des angeklickten Elementes. Bei allen weiteren Durchläufen wird außerhalb von ajaxStop die richtige ID, innerhalb des ajaxStop die erste angeklickte ID ausgegeben.

Wieso ist das so? Außerhalb ist pane ein Wert, innerhalb ein anderer? Wie kann ich das beheben?

Grüße, JN

--
ie:{ fl:( br:^ va:| ls:[ fo:| rl:? n4:? ss:| de:] js:| ch:? sh:( mo:| zu:)
http://www.johny7.de
  1. $('.pane').click(function(){
    var pane = $(this).attr('ID');
    alert(pane);
    $('#'+pane).load('newfile.html');
    $('#'+pane).ajaxStop(function () { alert('nach AJAX' + pane); });
    });

      
    
    > Der HTML-Aufbau sieht folgendermaßen aus:  
    > ~~~html
      
    
    > <div class="pane" id="pane1"></div>  
    > <div class="pane" id="pane2"></div>  
    > <div class="pane" id="pane3"></div>  
    > <div class="pane" id="pane4"></div>  
    > 
    
    

    Die ids sind nicht notwendig, wenn du schon ein Framework verwendest, dass dir Arbeit abnimmt, solltest du das auch nutzen und nicht erstrecht wieder kompliziert herumwerken.

    Folendes sollte reichen.

    $('.pane').click(function(){
      $(this).load('newfile.html').ajaxStop(function () { alert('nach AJAX' + pane); });
    });

    Aus Gründen der Übersichtlichkeit (und vor allem Logik) würde ich an deiner Stelle aber .ajax() mit success (anstatt load) und complete (anstatt ajaxStop).

    Wieso ist das so? Außerhalb ist pane ein Wert, innerhalb ein anderer? Wie kann ich das beheben?

    Weil ajaxStop global gesetzt wird und dann für alle beendeten ajax-Dingensen gilt, ist success/complete nur für den jeweiligen Request da - das steht auch in der Doku so.

    1. Weil ajaxStop global gesetzt wird und dann für alle beendeten ajax-Dingensen gilt, ist success/complete nur für den jeweiligen Request da - das steht auch in der Doku so.

      Nachtrag: natürlich kann das $(this)-Schlüsselwort auch bei ajaxStop genutzt werden, imho ist das aber dann eben zerpflückt und nicht mehr schlüssig - besonders bei gekapselten kleineren Anwendungen.

      Eine großte Seite die stark ajaxifiziert ist z.B. bei jedem Ajax-Aufruf denselben Ladekreisel an derselben stelle einfügt usw ist diese Lösung aber schlauer.

    2. Moin allerseits,

      Die ids sind nicht notwendig, wenn du schon ein Framework verwendest, dass dir Arbeit abnimmt, solltest du das auch nutzen und nicht erstrecht wieder kompliziert herumwerken.

      Ich weiß. Ich habe das absichtlich gemacht, um das this-Objekt zu umgehen. Aber jetzt habe ich verstanden, wie das funktioniert.

        
      <html xmlns="http://www.w3.org/1999/xhtml">  
      <head>  
      	<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />  
      	<title>clubworks</title>  
      	<script type="text/javascript" src="includes/js/jquery.js"></script>  
      	<script type="text/javascript">  
      	jQuery(  
      		function()  
      		{  
      			$('.pane').bind('click',function(){  
      					$(this).load('newfile.php');  
      					$(this).ajaxComplete(function () { alert('nach AJAX: ' + $(this).attr('ID')); });  
      			});  
      		}  
      	);  
      	</script>  
      	<style>  
      	.pane  
      	{  
      		padding:5px;  
      		border:1px solid red;  
      		width:300px;  
      		height:300px;  
      		margin:10px;  
      	}  
      	</style>  
      </head>  
      <body>  
      <div class="pane" id="pane1"></div>  
      <div class="pane" id="pane2"></div>  
      <div class="pane" id="pane3"></div>  
      <div class="pane" id="pane4"></div>  
      </body>  
      </html>  
      
      

      Weil ajaxStop global gesetzt wird und dann für alle beendeten ajax-Dingensen gilt, ist success/complete nur für den jeweiligen Request da - das steht auch in der Doku so.

      Ich habe jetzt auf ajaxComplete umgestellt. Trotzdem liefert er mir die ganze Schlange der bereits geladenen Elemente. Muss ich zwingend von load() umsteigen? Wozu braucht man dann noch diese Funktionen, wenn man in AJAX einfach einfach unter success: bestimmen kann, was gemacht werden soll? Nur wegen des Komforts?

      Gibt es denn irgend eine Möglichkeit, bei Verwendung von load() nur das zuletzt geladene Objekt zu bekommen? Wofür setzt man denn bitteschön das Objekt vor ajaxStop()? Damit alle geladenen Objekte angezeigt werden?

      Grüße, JN

      --
      ie:{ fl:( br:^ va:| ls:[ fo:| rl:? n4:? ss:| de:] js:| ch:? sh:( mo:| zu:)
      http://www.johny7.de
      1. Ich habe jetzt auf ajaxComplete umgestellt.

        Dasselbe - auch das ist global zu sehen.

        Trotzdem liefert er mir die ganze Schlange der bereits geladenen Elemente. Muss ich zwingend von load() umsteigen?

        Wozu braucht man dann noch diese Funktionen, wenn man in AJAX einfach einfach unter success: bestimmen kann, was gemacht werden soll? Nur wegen des Komforts?

        Ja, jQuery ist ein JavaScript-Framework, dort ist quasi alles nur wegen dem Komfort.

        Gibt es denn irgend eine Möglichkeit, bei Verwendung von load() nur das zuletzt geladene Objekt zu bekommen?

        Ich verstehe deine Frage nicht.

        Wofür setzt man denn bitteschön das Objekt vor ajaxStop()? Damit alle geladenen Objekte angezeigt werden?

        Nein, damit nachdem "alle" Ajax-Requests beendet wurden irgendwas passiert ohne es in jedem event extra definieren zu müssen.

        1. Moin allerseits,

          Ich habe jetzt auf ajaxComplete umgestellt.
          ist success/complete nur für den jeweiligen Request da
          Dasselbe - auch das ist global zu sehen.

          Welche Aussage stimmt nun?

          Gibt es denn irgend eine Möglichkeit, bei Verwendung von load() nur das zuletzt geladene Objekt zu bekommen?

          Ich verstehe deine Frage nicht.

          Ich meine, wenn ich die Datei per load() lade (siehe weiter unten)

          Wofür setzt man denn bitteschön das Objekt vor ajaxStop()? Damit alle geladenen Objekte angezeigt werden?

          Nein, damit nachdem "alle" Ajax-Requests beendet wurden irgendwas passiert ohne es in jedem event extra definieren zu müssen.

          Ja, das meine ich ja.

          Wie kann ich aber erreichen, dass nach dem Laden eines bestimmten Objektes nur mit diesem Objekt etwas passiert?

          Grüße, JN

          --
          ie:{ fl:( br:^ va:| ls:[ fo:| rl:? n4:? ss:| de:] js:| ch:? sh:( mo:| zu:)
          http://www.johny7.de
          1. Ich habe jetzt auf ajaxComplete umgestellt.
            ist success/complete nur für den jeweiligen Request da
            Dasselbe - auch das ist global zu sehen.
            Welche Aussage stimmt nun?

            Ich meinte damit du sollst .ajax() verwenden und dort success und complete und nicht du sollst .ajaxComplete() verwenden ;)

            Wie kann ich aber erreichen, dass nach dem Laden eines bestimmten Objektes nur mit diesem Objekt etwas passiert?

            Arbeite mit ajax() da lässt sich in den callback-Funktionen wesentlich "feiner" abstimmen was wann womit passiert.

            Aber auch bei load() bekommst du nur ein Objekt daher, das des jeweiligen Requests.

            Kannst du ggf. mal dein bisheriges Zeug online stellen, so ist das etwa mühseelig :)

            1. Moin allerseits,

              Ich habe jetzt auf ajaxComplete umgestellt.
              ist success/complete nur für den jeweiligen Request da
              Dasselbe - auch das ist global zu sehen.
              Welche Aussage stimmt nun?

              Ich meinte damit du sollst .ajax() verwenden und dort success und complete und nicht du sollst .ajaxComplete() verwenden ;)

              Wie kann ich aber erreichen, dass nach dem Laden eines bestimmten Objektes nur mit diesem Objekt etwas passiert?

              Arbeite mit ajax() da lässt sich in den callback-Funktionen wesentlich "feiner" abstimmen was wann womit passiert.

              Hm... dann muss  mein halbes Projekt umbauen. Ginge das nicht auch ohne?

              Aber auch bei load() bekommst du nur ein Objekt daher, das des jeweiligen Requests.

              Probier es unten aus, es kommen jedesmal mehrere Meldungen.

              Kannst du ggf. mal dein bisheriges Zeug online stellen, so ist das etwa mühseelig :)

              Bitte:
              http://johny7.bplaced.net/test/test.html

              Grüße, JN

              --
              ie:{ fl:( br:^ va:| ls:[ fo:| rl:? n4:? ss:| de:] js:| ch:? sh:( mo:| zu:)
              http://www.johny7.de
              1. Hm... dann muss  mein halbes Projekt umbauen.

                $.load('foo.html').

                gegen

                $.ajax({
                  url: 'foo.html',
                  success: function (response) {
                    alert('hello world' + response);
                  }
                });

                ersetzen halte ich nicht für sonderlich kompliziert ;)

                Ginge das nicht auch ohne?

                Natürlich, aber nicht so - du musst dir im klaren sein, dass .ajaxComplete() usw. global gesetzt und dann von allen load()-Aufrufen verwandt werden und bei dir jedes mal wenn sie aufgerufen werden wird ein neues hinzugefügt wird- nach dem 10. Klick hast du bereits 10x ein alert und es wird immer mehr.

                Aber auch bei load() bekommst du nur ein Objekt daher, das des jeweiligen Requests.
                Probier es unten aus, es kommen jedesmal mehrere Meldungen.

                Ja, weil du Complete jedes mal neu zuweist und sich immer wiederholt - das ist sicher so nicht gewollt.

                Darum ajaxComplete() ausserhalb bind()-Sache und nur 1x notieren.

                1. Moin allerseits,

                  jetzt habe ich das mit $.ajax() realisiert. Das sieht bei mir dann so aus:

                  $.ajax(  
                  {  
                  	//	Die Angaben werden aus einem Formular geholt  
                     url: runscript,  
                     type: runmethod,  
                     //	zusammengepuzzlete Daten  
                     data: input,	  
                     success: function (data) {  
                  		//	Das Formular wird mit dem Ergebnis des Scripts ersetzt  
                  		form.replaceWith(data);  
                  		//	Jetzt will ich mit dieser Funktion die neu geladenen Inhalte mit Event-Helpern ausstatten  
                  		form.CW_activateSpecificArea();  
                  		//	Zeigt mir aber noch die alten Inhalte, nicht die ersetzten  
                  		alert(form.html());  
                  	}	  
                  });	
                  

                  Offensichtlich versuche ich noch mit dem Objekt zu arbeiten, das ersetzt werden soll. Wie bekomme ich das neue Element? Ich habe es jetzt so versucht:

                    
                  $.ajax(  
                  {  
                     url: runscript,  
                     type: runmethod,  
                     data: input,	  
                     success: function (data) {  
                  		var newcontent = form.parent();  
                  		form.replaceWith(data);  
                  		newcontent.CW_activateSpecificArea();  
                  		alert(newcontent.html());  
                  	}	  
                  });		  
                  
                  

                  Aber theoretisch will ich gar nicht das Elternelement (es existiert schon, ist unverändert und war schon mit Event-Helpern ausgestattet), sondern die neuen Elemente. Geht das denn in der Kombination ~~~javascript form.replaceWith(data);
                  var newcontent = form.parent().children();

                    
                    
                  Grüße, JN
                  
                  -- 
                  ie:{ fl:( br:^ va:| ls:[ fo:| rl:? n4:? ss:| de:] js:| ch:? sh:( mo:| zu:)  
                  http://www.johny7.de
                  
                  1. Aber theoretisch will ich gar nicht das Elternelement (es existiert schon, ist unverändert und war schon mit Event-Helpern ausgestattet), sondern die neuen Elemente. Geht das denn in der Kombination ~~~javascript

                    form.replaceWith(data);

                    var newcontent = form.parent().children();

                      
                    Was tut "runscript", "runmethod", "input" oder "form"?  
                      
                    Aus gründen der Logik solltest du mit jQuery-Selektoren arbeiten, dann kannst du besser kontrollieren, was du selektierst.  
                      
                    Wenn du den inhalt eines Formulars verändern willst:  
                      
                    $('form[name=foo]').replaceWith(data);  
                      
                    Du wurstelst irgendwas mit form.parent() herum, wo ich jetzt nicht weiß wo das herkommt - dass da etwas mehr ersetzt wird als nur der Inhalt, sollte klar sein.  
                    
                    
                    1. Moin allerseits,

                      Was tut "runscript", "runmethod", "input" oder "form"?

                      Habe ich doch auskommentiert! runscript, runmethod und input werden aus dem Formular ermittelt und sind das mit action: auf zu rufende Script, dieÜbertragungsmethode und die Formulardaten. form ist das Formularobjekt.

                      Aus gründen der Logik solltest du mit jQuery-Selektoren arbeiten, dann kannst du besser kontrollieren, was du selektierst.

                      Ich kann dir natürlich, wenn du es gerne willst, einen 136-Zeichen langen jQuery Selektor mitgeben. Aber ich habe es doch deswegen auskommentiert. Das Objekt mit diesem Selektor ist eben form zugewiesen.

                      Wenn du den inhalt eines Formulars verändern willst:

                      $('form[name=foo]').replaceWith(data);

                      Nö, ich schicke das Formular mit ajax ab und ersetze es durch die Rückgabe des ausgeführten Scripts.

                      Du wurstelst irgendwas mit form.parent() herum, wo ich jetzt nicht weiß wo das herkommt - dass da etwas mehr ersetzt wird als nur der Inhalt, sollte klar sein.

                      Selbstverständlich. Das will ich ja auch. Die Formulardaten sind abgeschickt, das Formular muss verschwinden, stattdessen sollen die Rückgabeinhalte ausgegeben werden.

                      Grüße, JN

                      --
                      ie:{ fl:( br:^ va:| ls:[ fo:| rl:? n4:? ss:| de:] js:| ch:? sh:( mo:| zu:)
                      http://www.johny7.de
                      1. Habe ich doch auskommentiert! runscript, runmethod und input werden aus dem Formular ermittelt und sind das mit action: auf zu rufende Script, dieÜbertragungsmethode und die Formulardaten. form ist das Formularobjekt.

                        Alsob ich das "zusammengepuzzelte datten" hätet wissen sollen ;)

                        $('form[name=foo]').replaceWith(data);
                        Nö, ich schicke das Formular mit ajax ab und ersetze es durch die Rückgabe des ausgeführten Scripts.

                        Was ist die Rückgabe? Ein Array mit Fehlermeldungen, ein Vollständiges HTML-Formular?

                        Am Anfang dieses Threads waren es noch div-Elemente deren Inhalt getauscht werden soll - entscheide dich :)

                        Selbstverständlich. Das will ich ja auch. Die Formulardaten sind abgeschickt, das Formular muss verschwinden, stattdessen sollen die Rückgabeinhalte ausgegeben werden.

                        Siehe oben.

                        1. Moin allerseits,

                          Was ist die Rückgabe? Ein Array mit Fehlermeldungen, ein Vollständiges HTML-Formular?

                          Die Rückgabe ist HTML. In meinem Fall ist das z.B. ein div-Element mit Inhalt. Es kann aber auch ein neues Formular sein, je nachdem, was das Script zurückgibt.

                          Am Anfang dieses Threads waren es noch div-Elemente deren Inhalt getauscht werden soll - entscheide dich :)

                          Das stimmt. Am Anfang des Threads habe ich auch div-Elemente ausgetauscht. Hier sende ich ein Formular per AJAX und ersetze es durch das, was zurückkommt (siehe oben).

                          Grüße, JN

                          --
                          ie:{ fl:( br:^ va:| ls:[ fo:| rl:? n4:? ss:| de:] js:| ch:? sh:( mo:| zu:)
                          http://www.johny7.de
                          1. Die Rückgabe ist HTML. In meinem Fall ist das z.B. ein div-Element mit Inhalt. Es kann aber auch ein neues Formular sein, je nachdem, was das Script zurückgibt.

                            Da solltest du dich einigen ;)

                            Das stimmt. Am Anfang des Threads habe ich auch div-Elemente ausgetauscht. Hier sende ich ein Formular per AJAX und ersetze es durch das, was zurückkommt (siehe oben).

                            Das funktioniert aber genauso - du musst nur dafür sorgen, dass der zurückgegebene HTML-Code dafür geeignet ist.

                            <div class="formmailer">  
                              <form />  
                            </div>
                            

                            ob da nun bei der Antwort ein neues Formular daherkommt oder ein "Danke für's Abschicken" ist dir dann egal wenn du nur den inhalt von .formmailer ersetzt.