Knockout.js получает объект dom, связанный с данными
Я работаю с knockout.js для создания динамических списков, и я пытаюсь выяснить, как я могу получить объект DOM, связанный с объектом в моем наблюдаемом массиве. В частности, я хочу получить jQuery для строки.
Пример:
<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?
Ответы
Ответ 1
Обработчики событий, такие как click, передают два аргумента. Это а) элемент, к которому относится это событие, - как запись наблюдаемого массива, который вы визуализируете с привязкой foreach ( "Item" в вашем случае). И б) объект события, который предоставляет вам больше информации о фактическом событии. Этот объект содержит элемент DOM, на который был нажат (ключ "target" ):
getDomObject = function(item, event) {
var $this = $(event.target);
// ...
}
Просто заметьте: не смешивайте нокауты и собственные манипуляции с DQ JQuery - если вы можете добиться того же результата с помощью умных привязок нокаута, я бы порекомендовал, чтобы с этим.
И вот простая демонстрация: http://jsfiddle.net/KLK9Z/213/
Ответ 2
Решение $(event.target) хорошо, если оно связано с уже происходящим событием, в котором элемент DOM элемента находится в объекте. Но иногда у вас нет целевого элемента, потому что нет события (например, вы хотите прокрутить список к элементу, который не был указан пользователем).
В таком случае вы можете присвоить атрибуту id элемента элемента DOM уникальное значение, которое содержит идентификатор элемента:
<li data-bind="attr: {id: 'item_' + id}">
а затем getDomObject() выглядит так:
getDomObject = function(item) { return $("#item_" + item.id); }
Ответ 3
Чтобы добавить еще третий вариант, также для случаев, когда у вас нет события для работы (если у вас есть событие, принятый ответ лучше/оптимизирован).
Создайте настраиваемую привязку, например:
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">
В приведенном выше случае $parent является моей моделью просмотра. У меня есть наблюдаемый объект, который содержит уникальный идентификатор. Каждый раз, когда я устанавливаю этот объект scrollTo(), список прокручивается к этому элементу.
Обратите внимание, что мой код предполагает, что родительский DIV LI имеет полосу прокрутки (переполнение: авто/прокрутка). Вы можете настроить для своих нужд, возможно, использовать класс для родителя и использовать его для вашего селектора jQuery или сделать очень гибким, чтобы вы могли перейти в селектор через параметры привязки данных... для меня этого было достаточно, поскольку Я всегда использую divs для моих прокручиваемых разделов.
Ответ 4
У меня была аналогичная проблема. Я придумываю решение, напоминающее 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>
в bindHandlers (показывая все возможные аргументы для 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, например:
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");
}
}
Надеюсь, это поможет!
Ответ 5
Мое решение (допустимо для привязки "значение" )
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. $el и yourobservable.el, которые привязываются к элементу jquery и DOM.