Knockout.js получает объект dom, связанный с данными - программирование
Подтвердить что ты не робот

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?

4b9b3361

Ответ 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.