2012-04-12 2 views
46

Я работаю с knockout.js для создания динамических списков, и я пытаюсь выяснить, как я могу получить объект DOM, связанный с объектом в моем наблюдаемом массиве. В частности, я хочу получить jQuery для строки.Knockout.js получить объект dom, связанный с данными

Пример:

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

в функции getDomObject, я хотел бы быть в состоянии получить конкретный объект <li></li> DOM, так что я могу сделать некоторые манипуляции JQuery с ним.

Я подумал о том, чтобы добавить элемент id в элемент ViewModel, а затем добавить идентификатор в качестве идентификатора html позиции и затем выбрать его на основе этого, но я считаю, что должен быть более простой способ.

Каков правильный способ ссылки на динамический HTML, созданный knockout.js?

ответ

64

Обработчики событий, такие как щелчок, получают два аргумента. Это а) элемент, к которому относится это событие, - как запись наблюдаемого массива, который вы визуализируете с привязкой foreach («Item» в вашем случае). И б) объект события, который предоставляет вам больше информации о фактическом событии. Этот объект содержит элемент DOM, который получил щелкнули (ключ «мишень»):

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

Просто примечание: Не смешивать нокаута и родные манипуляции DOM JQuery - если вы можете достичь того же результата с умными привязок нокаута , Я бы порекомендовал пойти с этим.

А вот простой демо: http://jsfiddle.net/KLK9Z/213/

+0

спасибо! Это отлично работает! Спасибо за советы по поводу манипуляции jQuery. Я использую автозаполнение на определенных строках, поэтому я не думаю, что смогу сделать это через ko. Отличное решение –

+0

использует пользовательские привязки для автозаполнения padawan. : P одна вещь, которую я узнал после трех месяцев работы с ko: использование пользовательских привязок с помощью jquery/jquery ui. –

+0

Я много лет работал с нокаутом и не знал о параметре события - блестяще! спасибо –

20

$ (event.target) решение хорошо, если это связано с уже произошедшим событием, в котором DOM элемент элемента не на цели. Но иногда у вас нет целевого элемента, потому что нет события (например, вы хотите прокрутить список к элементу, который не был указан пользователем).

В таком случае вы можете дать DOM элемент Идентификатор элемента атрибута уникальное значение, которое содержит идентификатор товара:

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

, а затем getDomObject() выглядит следующим образом:

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

ИМХО, этот ответ гораздо более полна именно по той причине, о которой говорил yuvalr80. –

+0

Этот ответ был тем, что мне нужно, но принятый ответ лучше для исходного вопроса. Спасибо за отправку этого ответа, хотя, именно то, что мне нужно. Не сумасшедший по поводу пересечения линий MVVM, но мне просто нужен эффективный способ прокрутки элемента для просмотра, и я не хочу добавлять лишние наблюдаемые для каждого объекта в моем списке только для этого. – eselk

+1

Он работает, но передает идентификатор, а затем получает DOM этим идентификатором. Это нарушает некоторые правила. Любое решение, отличное от ID, было бы очень оценено. –

7

Чтобы добавить еще третий вариант, также для случаев, когда у вас нет события для работы (если у вас есть событие, принятый ответ лучше/оптимизирован).

Создание пользовательской привязки, такие как:

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); 
     } 
    } 
}; 

использование выглядит следующим образом:

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

В приведенном выше случае, $ родитель мой взгляд модель. У меня есть наблюдаемый объект, который содержит уникальный идентификатор. Каждый раз, когда я устанавливаю этот объект scrollTo(), список прокручивается к этому элементу.

Обратите внимание, что мой код предполагает, что родительский DIV LI имеет полосу прокрутки (переполнение: авто/прокрутка). Вы можете настроить для своих нужд, возможно, использовать класс в родительском объекте и использовать его для вашего селектора jQuery, или сделать очень гибким, вы можете перейти в селектор через параметры привязки данных ...для меня этого было достаточно, поскольку я всегда использовал divs для своих прокручиваемых разделов.

+0

Я сделал что-то подобное, и он работает очень хорошо! Спасибо за сообщение –

1

У меня была аналогичная проблема. Я придумал решение, напоминающее Backbone.js, использование ссылок el и $ el.

в вашем ViewModel:

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

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

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

в HTML (например, список элементов):

<!-- 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> 

в bindingHandlers (показать все возможные аргументы 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()); 
    } 
}; 

Например, вы можете использовать $ el like:

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"); 
    } 
} 

Надеюсь, это поможет!

1

Мое решение (действительно для "значения" связывания)

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); 
} 

Теперь у вас есть yourobservable. $ Эш и yourobservable.el, которые связываются с JQuery и DOM элемента.

Смежные вопросы