Frage

Ich habe eine Webanwendung basierend auf Apache, PHP, js / jquery.Ein Modul der Anwendung wird beim Laden des Dokuments initialisiert.Diese Sequenz ruft eine init () -Funktion auf, die eine Reihe von Aufgaben ausführt, unter anderem holt sie zwei HTML-Dialoge über Ajax und fügt sie in die vorhandene Seite ein.Ein Verweis auf diese Dialoge wird als Variablen gespeichert, sodass ich in meinen Skripten keine Jquery-Selektoren angeben muss, sondern stattdessen einfach diese Variablen verwenden kann.Das funktioniert gut, außer dass es sehr wenige Fälle gibt (ab und zu...), wenn die Variablen 'undefiniert' sind, wenn versucht wird, einen Handler an ein Element in den abgerufenen Dialogen zu binden.Was seltsam ist, denn abgesehen davon sind die Dialoge in der gesamten Anwendung verwendbar.Dies deutet darauf hin, dass die Ajax-Aufrufe erfolgreich sind, aber anscheinend gibt es eine Art Rennbedingung, so dass ab und zu nur die Variablen gesetzt werden nach der Bindungsversuch.

Nach meinem Verständnis sollte dies nicht passieren, da die Bindung in der erfolgt.done() ist Teil eines when() und sollte erst ausgeführt werden, nachdem der Ajax-Abruf der Dialoge innerhalb von when() abgeschlossen ist.

Anscheinend fehlt mir hier etwas Grundlegendes.Hat jemand einen Tipp für mich?

Im Folgenden werden Codeauszüge aus der funktionierenden Implementierung zitiert.Sie können als einige Teile syntaktisch ungültig erscheinen, aber das liegt nur an der Entfernung von Codeteilen, die hier nicht relevant sind.Der ungekürzte Code funktioniert einwandfrei.

Variabel:

Shorty.Tracking.Dialog.List:{};
Shorty.Tracking.Dialog.Click:{};

Die Initialisierungssequenz:

$(window).load(function(){
  //...
  var dfd = new $.Deferred();
  $.when(
    // load layout of dialog to show the list of tracked clicks
    Shorty.Tracking.init()
  ).done(function(){
    // bind actions to basic buttons
    Shorty.Tracking.Dialog.List.find('#close').on('click',function(){
      // ...
    });
    // ...
  });
  // ...
})

Die verkürzte Init-Funktion:

Shorty.Tracking.init:function(){
    // ...
    var dfd=new $.Deferred();
    // two dialogs are used by this plugin
    var dialogs={
      'list':  Shorty.Tracking.Dialog.List,
      'click': Shorty.Tracking.Dialog.Click
    };
    // load dialogs from server
    $.each(['list','click'],function(i,dialog){
      if (...){
        // ...
        dfd.resolve();
      }else{
        // load dialog layout via ajax and create a freshly populated dialog
        $.ajax({
          type:     'GET',
          url:      OC.filePath('shorty-tracking','ajax','layout.php'),
          data:     { dialog: dialog},
          cache:    false,
          dataType: 'json'
        }).pipe(
          function(response){return Shorty.Ajax.eval(response)},
          function(response){return Shorty.Ajax.fail(response)}
        ).done(function(response){
          // create a fresh dialog
          // insert it alongside the existing dialogs in the top controls bar
          $('#controls').append(response.layout);
          switch (dialog){
            case 'list':
              Shorty.Tracking.Dialog.List=$('#controls #shorty-tracking-list-dialog').first();
              break;
            case 'click':
              Shorty.Tracking.Dialog.Click=$('#controls #shorty-tracking-click-dialog').first();
          } // switch
          dfd.resolve();
        }).fail(dfd.reject)
      } // else
    }); // each
    return dfd.promise();
  },

Mit der Antwort von Bergi gelang es mir anscheinend, das ursprüngliche Problem zu beseitigen.Bis jetzt konnte ich keine fehlgeschlagenen Bindeversuche mehr feststellen.Diesem Vorschlag konnte ich jedoch nicht vollständig folgen:in seiner Antwort schlug er vor, die switch-Anweisung in der Initialisierungsmethode zugunsten einer direkten Zuweisung zu entfernen.Das ist sicherlich viel eleganter, aber das wird nicht funktionieren.Ich habe den Eindruck, dass es auf meiner Seite ein Missverständnis darüber gibt, wie Javascript mit in Variablen gespeicherten Referenzen und / oder Funktionen umgeht.

Vielleicht kannst du, Bergi, oder jemand anderes etwas erklärendes Licht darauf werfen:

Dies ist die modifizierte Initialisierungsmethode von oben:

  init:function(){
    if (Shorty.Debug) Shorty.Debug.log("initializing tracking list");
    // check if dialogs already exist
    if (   $.isEmptyObject(Shorty.Tracking.Dialog.List)
        && $.isEmptyObject(Shorty.Tracking.Dialog.Click) ){
      // two dialogs are used by this plugin
      var dialogs={
        'list':  Shorty.Tracking.Dialog.List,
        'click': Shorty.Tracking.Dialog.Click
      };
      // load dialogs from server
      var dfds=$.map(dialogs,function(obj,dialog){
        // load dialog layout via ajax and append it to the collection of dialogs in the controls
        return $.ajax({
          type:     'GET',
          url:      OC.filePath('shorty-tracking','ajax','layout.php'),
          data:     { dialog: dialog},
          cache:    false,
          dataType: 'json'
        }).pipe(
          function(response){return Shorty.Ajax.eval(response)},
          function(response){return Shorty.Ajax.fail(response)}
        ).done(function(response){
          // create a fresh dialog and insert it alongside the existing dialogs in the top controls bar
          $('#controls').append(response.layout);
//           obj=$('#controls #shorty-tracking-'+dialog+'-dialog').first();
          switch(dialog){
            case 'list':
              Shorty.Tracking.Dialog.List=$('#controls #shorty-tracking-list-dialog').first();
              break;
            case 'click':
              Shorty.Tracking.Dialog.Click=$('#controls #shorty-tracking-click-dialog').first();
              break;
          } // switch
        })
      }) // map
      return $.when.apply(null, dfds);
    }else{
      // dialogs already loaded, just clean them for usage
      Shorty.Tracking.Dialog.List.find('#list-of-clicks tbody tr').remove();
      new Deferred().resolve();
    } // else
  },

In der Mitte sehen Sie die auskommentierte Zuweisungsanweisung, die derzeit durch die unten stehende switch Anweisung ersetzt wird.Ich habe verschiedene Variationen ausprobiert, wie obj .element und so weiter, aber fehlgeschlagen.Außerhalb der Funktion sind die Variablen Kurz.Tracking.Dialog.Liste und Shorty.Tracking.-Dialog.Klicken Sie auf leer bleiben.

Ich bin ein absoluter Neuling in Sachen Web und js / jquery.aber ich bin auf jeden Fall neugierig, mehr über diese Art des Umgangs mit Referenzen zu erfahren.

War es hilfreich?

Lösung

Das ist der problematische Code:

var dfd=new $.Deferred();
$.each(['list','click'], function(){
    ...
    dfd.resolve/fail();
});

Sie erstellen nur eine aufgeschobene, lösen sie jedoch mehrmals auf.Wenn also die erste Auflösung erfolgt, wäre der zweite Ajax nicht fertig gewesen.

Verwenden Sie stattdessen zwei Aufschiebungen und kombinieren Sie sie durch jQuery.when().Ich glaube auch nicht, dass Sie selbst Verzögerungen erstellen müssen.Nimm einfach die beiden, die du von der bekommst pipe() nennen.

function init() {
   var dialogs={
      'list':  Shorty.Tracking.Dialog.List,
      'click': Shorty.Tracking.Dialog.Click
   };
   var deferreds = $.map(dialogs, function(obj, dialog) {
       return $.ajax(...).pipe(...).done(...
           // really, don't use switch here:
           obj.element = response.layout;
       }); // done() returns the Deferred
   });
   return $.when.apply(null, deferreds);
}

...

$.ready(function($) {
    init().done(...);
});

OK, ich muss die Switch-Anweisung erklären.Es ist wahr, die Werte in der dialogs objekt wird aus [nicht initialisierten] Variablen zugewiesen und enthält diesen Wert (undefined), wenn die Felder neu zugewiesen werden die Shorty werte werden sich nicht ändern.Es gibt keine "Zeiger" in Javascript.Ich dachte nur, es wäre nützlich, den Strom zu verwenden dialog variable in einem Elementoperator anstelle einer switch-Anweisung.Zuweisen zu Shorty.Tracking.Dialog.List und .Click, müssten Sie etwas wie verwenden

var dialogs = ["list", "click"];
var shortcut = Shorty.Tracking.Dialog; // some object
for (var i=0; i<dialogs.length; i++) {
    // loop over them,
    // do the ajax stuff
    var element = $(repsonse.layout); // get the added element from the response
    $('#controls').append(element);

    shortcut[dialogs[i]] = element;
}

(verwenden Sie eventuell einen Ausschnitt aus Wie mache ich den ersten Buchstaben einer Zeichenfolge in JavaScript in Großbuchstaben?)

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top