2017-02-07 4 views
0

Ich verwende $ .observable (array) .insert(), um Elemente an eine Liste anzuhängen. Das aktualisiert meine Ansicht, wie es sollte: neue Listenelemente werden an das DOM gerendert. Ich möchte jedoch ein Klickereignis für den neuen DOM-Knoten ausgeben (ich verlasse mich auf das Ereignis, um eine Klasse hinzuzufügen, um das Element zu erweitern und einen anderen Listener an den Hauptteil anzuhängen, damit der Bereich geschlossen werden kann).

Ich habe beide versucht

$.observable(_model.leadTimes).insert(leadTime); 
$leadTimes.find('.lead-time-data').last().find('.start-editing').click(); 

... und

function watchLeadTimes() { 

    var changeHandler = function (ev, eventArgs) { 
     if (eventArgs.change === 'insert') { 

      $leadTimes.find('.lead-time-data').last().find('.start-editing').click(); 

     } 
    }; 

    $.observe(_model.leadTimes, changeHandler); 

} 

Und keiner von ihnen arbeitete, jedoch, wenn ich die jQuery-Methode in einem setTimout wickeln, wie setTimeout(function() { $leadTimes.find('.lead-time-data').last().find('.start-editing').click(); }, 400);, es funktioniert Arbeit, führe mich zu glauben, dass dies ein Problem des Timings mit dem DOM Render irgendwie nicht fertig ist, bevor meine jQuery click() -Methode aufgerufen wird.

Da die Chancen sind anständig, dass Sie dies sehen werden, Borris, danke für die Bibliothek und alles, was Sie tun! Ich denke, jsViews ist ein exzellenter Mittelweg zwischen den monolithischen Frameworks da draußen und dem einfachen alten jQuery noodling!


bearbeiten 02/09/17

Es stellt sich heraus mein Problem überlappende Klick-Ereignisse - ich versehentlich einen Klick wurde Umgang mit meinem Element abzuwählen unmittelbar nach dem ausgewählt wurde. Allerdings nutzte ich die Gelegenheit, um die Dinge neu zu schreiben, um einen mehr deklarativen Ansatz zu verwenden, der dem verknüpften Beispiel von Borris folgt.

Jetzt in meiner Vorlage verwende ich einen beobachtbaren berechnet, isSelected die .editing Klasse zu wechseln:

{^{for leadTimes}} 
    <tr class="lead-time-data" data-link="class{merge:~isSelected() toggle='editing'}"> 
     <span>{^{:daysLead}}</span> 
    </tr> 
{{/for}} 

Und das JS:

function addNewLeadTimeClickHandler() { 

    var onNewLeadTimeClick = function() { 

     e.stopPropagation(); // this is what I was missing 

     var leadTime = { 
      daysLead: 1, 
      description: '' 
     }; 

     $.observable(_model.activityMapping.leadTimes).insert(leadTime); 
     selectLeadtime(_model.activityMapping.leadTimes.length -1); 

    } 
    $leadTimes.on('click', '.add', onNewLeadTimeClick); 

} 

function selectLeadtime(index) { 

    var addStopEditingClickHandler = function() { 

     var onClickHandler = function (event) { 
      if ($(event.target).closest('tr').hasClass('editing')) { 
       setHandler(); 
       return; 
      } 

      selectLeadtime(-1) 

     }; 

     function setHandler() { 
      var clickEvent = 'click.ActivityChangeRequestDetailController-outside-edit-row'; 
      $('html:not(.edit)').off(clickEvent).one(clickEvent, onClickHandler); 
     }; 

     setHandler(); 

    } 

    if (_model.selectedLeadtimeIndex !== index) { 
     $.observable(_model).setProperty('selectedLeadtimeIndex', index) 
     addStopEditingClickHandler(); 
    } 

} 
function isSelected() { 
    var view = this; 
    return this.index === _model.selectedLeadtimeIndex; 
} 
// isSelected.depends = ["_model^selectedLeadtimeIndex"]; 
// for some reason I could not get the above .depends syntax to work 
// ...or "_model.selectedLeadtimeIndex" or "_model.selectedLeadtimeIndex" 
// but this worked ... 
isSelected.depends = function() {return [_model, "selectedLeadtimeIndex"]}; 

Antwort

1

Die beobachtbare insert() Methode synchron ist. Wenn Ihre Listenelemente einfach unter Verwendung von {^{for}} gerendert werden, ist das auch synchron, daher sollten Sie setTimeout oder einen Rückruf nicht verwenden. (Es gibt solche Rückrufe zur Verfügung, aber Sie sollten sie nicht für dieses Szenario benötigen.)

Siehe zum Beispiel http://www.jsviews.com/#samples/editable/tags (Code here):

$.observable(movies).insert({...}); 
// Set selection on the added item 
app.select($.view(".movies tr:last").index); 

Die Auswahl wird immer hinzugefügt, synchron, auf die neu eingefügten Artikel.

Haben Sie irgendwo anderen asynchronen Code in Ihrem Rendering?

In der Regel müssen Sie keine neuen Klickhandler hinzufügen, wenn Sie das Delegatenmuster verwenden. Beispiel: Im selben Beispiel wird ein Klick-Handler zum Entfernen eines Films zunächst dem Container "#movieList" mit einem Delegatenselektor ".removeMovie" hinzugefügt (siehe code). Das funktioniert auch für später hinzugefügte Filme.

Das gleiche Szenario funktioniert {{on}} Siehe mit http://www.jsviews.com/#link-events: „Das Selektor Argument Elemente ausrichten kann, die später hinzugefügt werden“

+0

Dank für die Führung; Ich werde das untersuchen! Das Klickereignis, das ich hinzufügen/entfernen wollte, befindet sich im Körper. Die Idee ist, dass ich ein Klick-Ereignis auf das neue Element triggere, sodass es beim Hinzufügen erweitert wird, und der Benutzer kann außerhalb (auf dem Körper) klicken, um es zu schließen. Ich betrachte einen eher deklarativen Ansatz, der dem oben verlinkten Beispiel ähnelt. – HowlingFantods

Verwandte Themen