2012-04-12 5 views
46

Ich arbeite mit knockout.js, um dynamische Listen zu erstellen, und ich versuche herauszufinden, wie ich das DOM-Objekt mit einem Objekt in meinem beobachtbaren Array erhalten kann. Speziell möchte ich die jQuery für eine Zeile bekommen.Knockout.js get dom Objekt mit Daten verbunden

Beispiel:

<ul data-bind="foreach: Item"> 
    <li data-bind="events: {click: getDomObject}, text: 'text: ' + text"> 
    </li> 
</ul> 

in der getDomObject Funktion, würde Ich mag Lage sein, das spezifische <li></li> DOM-Objekt zu erhalten, so dass ich mit ihm einige jQuery Manipulation zu tun.

Ich habe darüber nachgedacht, ein Element id dem Item ViewModel hinzuzufügen und dann die ID als die HTML-ID der Werbebuchung hinzuzufügen und dann basierend darauf auszuwählen, aber ich denke, dass es einen einfacheren Weg geben sollte.

Was ist der richtige Weg, um das von knockout.js generierte dynamische HTML zu referenzieren?

Antwort

64

Event-Handler wie Klick erhalten zwei Argumente übergeben. Das ist a) das Element, zu dem dieses Ereignis gehört - wie der Eintrag eines beobachtbaren Arrays, das Sie mit der foreach-Bindung rendern (in Ihrem Fall "Element"). Und b) ein Ereignisobjekt, das Ihnen mehr Informationen über das eigentliche Ereignis liefert. Dieses Objekt enthält das DOM-Element, das auf (Taste „target“) angeklickt wurde:

getDomObject = function(item, event) { 
    var $this = $(event.target); 
    // ... 
} 

Nur ein Hinweis: Verwenden Sie keine Kombination Knockout und nativen jQuery DOM-Manipulationen - wenn Sie das gleiche Ergebnis mit cleveren Knockout-Bindungen erzielen können Ich würde es empfehlen.

Und hier ist eine einfache Demo: http://jsfiddle.net/KLK9Z/213/

+0

Vielen Dank! Das funktioniert großartig! Danke für die Diskussionen über jQuery-Manipulation. Ich verwende die Autocomplete in bestimmten Zeilen, also glaube ich nicht, dass ich das über Ko machen kann. Tolle Lösung –

+0

Verwenden Sie die benutzerdefinierten Bindungen für die Autovervollständigung Padawan. : P eine Sache, die ich nach 3 Monaten gelernt habe mit Ko: Verwenden Sie benutzerdefinierte Bindungen mit jquery/jquery ui stuff. –

+0

Ich habe mit Knockout seit Ewigkeiten gearbeitet und wusste nicht, der Ereignisparameter - brilliant! danke –

20

Die $ (event.target) Lösung ist gut, wenn es zu einem bereits auftretenden Ereignisse verbunden ist, in dem das DOM-Element an Ziel ist Stück. Aber manchmal haben Sie das Zielobjekt nicht, weil es kein Ereignis gibt (zum Beispiel - Sie möchten durch eine Liste zu einem Element blättern, das nicht vom Benutzer gestikuliert wurde).

In einem solchen Fall können Sie die Sache des DOM-Element-ID geben einen eindeutigen Wert Attribut, das die Artikel-ID enthält:

<li data-bind="attr: {id: 'item_' + id}"> 

und dann getDomObject() wie folgt aussieht:

getDomObject = function(item) { return $("#item_" + item.id); } 
+0

IMHO, diese Antwort ist viel vollständiger für genau den Grund, den yuvalr80 angegeben. –

+0

Diese Antwort war was ich brauchte, aber die akzeptierte Antwort ist besser für die ursprüngliche Frage. Danke auch für das Posten dieser Antwort, genau was ich brauchte. Nicht verrückt, die MVVM-Linien zu überschreiten, aber ich brauchte nur eine effiziente Methode, um ein Objekt in der Ansicht zu scrollen, und ich habe nicht das Gefühl, zu jedem Objekt in meiner Liste extra ein Beobachtbares hinzuzufügen. – eselk

+1

Es funktioniert, aber die ID übergeben und dann das DOM von dieser ID erhalten. Es bricht einige Regeln. Jede Nicht-ID-Lösung würde sehr geschätzt werden. –

7

noch hinzufügen eine dritte Option, auch für Fälle, in denen Sie kein Ereignis haben, mit dem Sie arbeiten können (wenn Sie ein Ereignis haben, ist die akzeptierte Antwort am besten/optimiert).

eine benutzerdefinierte erstellen Bindung wie zum Beispiel:

ko.bindingHandlers.scrollTo = { 
    update: function(element, valueAccessor) { 
     var value = ko.utils.unwrapObservable(valueAccessor()); 
     if (value) { 
      var scrollParent = $(element).closest("div"); 
      var newTop = $(element).position().top + scrollParent.scrollTop(); 
      scrollParent.scrollTop(newTop); 
     } 
    } 
}; 

Nutzung wie folgt:

<li data-bind="scrollTo: $parent.scrollTo() && $parent.scrollTo().id == id"> 

Im obigen Fall ist $ parent meine Ansicht Modell. Ich habe ein beobachtbares Objekt, das eine eindeutige ID enthält. Jedes Mal, wenn ich das Objekt scrollTo() aktiviere, scrollt die Liste zu diesem Objekt.

Beachten Sie, dass mein Code davon ausgeht, dass der übergeordnete DIV der LI über die Bildlaufleiste verfügt (Überlauf: auto/scroll). Sie können sich an Ihre Bedürfnisse anpassen, möglicherweise eine Klasse für den Elternknoten verwenden und diese für Ihren jQuery-Selektor verwenden, oder um sehr flexibel zu sein, können Sie den Selektor über Ihre Datenbindungsoptionen übergeben ...Für mich war das genug, da ich für meine scrollbaren Abschnitte immer Divs verwende.

+0

Ich habe etwas ähnliches gemacht und es funktioniert ziemlich gut! Danke für die Post –

1

Ich hatte ein ähnliches Problem. Ich finde eine Lösung, die Backbone.js Verwendung von el und $ el Referenzen ähnelt.

in Ihrem Ansichtsmodell:

var myViewModel = function(){ 
    var self = this; 

    //html element 
    self.el = ko.observable(); 

    //jquery wrapped version 
    self.$el = ko.observable(); 
} 

in html (zB Listenelement):

<!-- left side is the name of the handler, right side is name of the observable --> 
<li class="myclass" data-bind="el: el, $el: $el"></li> 

in bindingHandlers (alle möglichen Argumente zeigt init):

ko.bindingHandlers.el = { 
    init: function(element, valueAccessor, allBindings, viewModel, bindingContext) { 
    var value = valueAccessor(); 
    //assign value to observable (we specified in html) 
    value(element); 
    } 
}; 

ko.bindingHandlers.$el = { 
    init: function(element, valueAccessor, allBindings, viewModel, bindingContext) { 
    var value = valueAccessor(); 
    //here we first create a jQuery object by using $(myelem) 
    //before updating observable value 
    value($(element).first()); 
    } 
}; 

Zum Beispiel können Sie dann $ el wie:verwenden

var myViewModel = function(){ 
    var self = this; 

    //plain DOM element reference 
    self.el = ko.observable(); 

    //jquery object reference 
    self.$el = ko.observable(); 

    self.myFunction = function() { 
    console.log(self.$el().html()); 
    self.$el().addClass("myCssClass"); 
    } 
} 

Hoffe, das hilft!

1

Meine Lösung (gültig für "Wert" Bindung)

ko.bindingHandlers.value.preprocess = function(val, name, cb) { 
    /* every time I set a data-bind="value: xxxx" with an 
    * observable xxxx add also a data-bind="domElement: xxxx" */ 
    cb('domElement', val); 
    return val; 
} 

ko.bindingHandlers.domElement = { 
    /* For each data-bind="domElement: xxxx" add an extension "element" */ 
    init: function (element, valueAccessor, allBindingsAccessor, viewModel) { 
     valueAccessor().extend({element: element }); 
    } 
    }; 

ko.extenders.element = function (target, element) { 
    /* element extension add el and $el to observable xxxx */ 
    target.el = element; 
    target.$el = $(element); 
} 

Jetzt Sie yourobservable haben. $ El und yourobservable.el, die jquery und DOM-Element binden.