KnockoutJS — почему обработчик инициализации привязки вызывается только один раз?

#javascript #jquery #knockout.js #twitter-bootstrap

#javascript #jquery #knockout.js #twitter-bootstrap

Вопрос:

У меня проблема, из-за которой функция init: не вызывается при втором обновлении данных с сервера.

Есть ли какая-либо причина, по которой это может произойти?

Я использую плагин сопоставления. Еще одна проблема, которую я не понимаю, заключается в том, нужно ли мне вызывать функцию плагина сопоставления по-разному в зависимости от того, является ли это 1-м вызовом или 2-м вызовом?

JS

  function ViewMemberPopup(memberId) {

        $.get("/People/GetMemberDetails?memberId="   memberId, function (data) {            
            viewMemberModel.model = ko.mapping.fromJS(data);            
            ko.applyBindings(viewMemberModel.model, $("#memberDetailsContainer")[0]);
        });
    }


 // binding handler
 ko.bindingHandlers.renderMemberModal = {
        init: function (element, valueAccessor, allBindingsAccessor) {
            $(element).modal("show");            
        }
    };
 

HTML:
Я использовал renderMemberModal:true для обработчика привязки, не уверен, зачем мне нужно привязанное к нему свойство. Мне просто нужно вызвать функцию рендеринга…

      <div class="modal fade" id="viewMemberModal" data-bind="renderMemberModal: true" style="display: none;">
        <div class="modal-header">
            <a class="close" href="#">×</a>
            <h3>
                Member Details</h3>
        </div>
        <div class="modal-body">
             <div data-bind="template: { name: 'memberDetailsTemplate' }">
            </div>
        </div>
        <div class="modal-footer">
            <a class="btnx closeModal">Close</a>
        </div>
    </div>
 

Я использую bootstrap css для отображения модального всплывающего окна.

Ответ №1:

Обычно вы не хотите продолжать вызывать applyBindings для одного и того же элемента при каждом обновлении. Это может привести к добавлению нескольких обработчиков событий в зависимости от используемых вами привязок. Если бы вы должны были это сделать, то вы хотели бы, по крайней мере, вызвать ko.cleanNode элемент. Что-то вроде: http://jsfiddle.net/rniemeyer/F4AzB /

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

Ваша ViewModel может иметь observable для представления ваших данных. Затем вы можете обновить это наблюдаемое новыми копиями ваших данных.

В этом случае, что вы действительно хотели бы сделать, так это иметь в вашей пользовательской привязке просто функцию обновления и обязательно обращаться к основному наблюдаемому, чтобы он срабатывал каждый раз, когда вы вызываете свою функцию обновления.

 ko.bindingHandlers.custom = {
    update: function(element, valueAccessor) {
        ko.utils.unwrapObservable(valueAccessor());  //just for subscription
        console.log("hit");
    }  
};
 

Будет выглядеть примерно так: http://jsfiddle.net/rniemeyer/dNsW8 /

Комментарии:

1. Просто пытаюсь разобраться и понять sample. ko.mapping.fromJS(dataFromServer, null, ViewModel.myData()) — почему 3 параметра, я думал, что требуется только 2? Есть ли какие-либо документы по этому поводу?

2. ko.mapping.fromJS может принимать три параметра. Первый — это данные, второй — параметры сопоставления, а третий — объект, который вы хотите обновить. Если вы имеете дело с уже отображенным объектом, который хотите обновить, вы можете передать его в качестве второго параметра, поскольку ему больше не нужны параметры сопоставления, и он распознает, что вы передали уже отображенный объект, а не параметры сопоставления.

3. Можете ли вы воспроизвести свою проблему в jsFiddle? Какую версию KO вы используете? Попробуйте использовать бета-версию 1.3 (или текущую сборку с github), $data доступен везде, а не только в шаблонах jQuery.

4. Я старался изо всех сил, но, боюсь, это просто не мой день, даже пользовательский интерфейс jquery не работает в скрипке после замены из bootstrap. jsfiddle.net/dNsW8/3

5. Спасибо, это мне очень помогло. Теперь у меня есть рабочее решение!

Ответ №2:

На сайте Knockoutjs http://knockoutjs.com/documentation/custom-bindings.html обсуждаются пользовательские привязки.

Knockout вызовет вашу функцию инициализации один раз для каждого элемента DOM, для которого вы используете привязку. Существует два основных способа использования init: — Для установки любого начального состояния для элемента DOM — Для регистрации любых обработчиков событий, чтобы, например, когда пользователь нажимает на элемент DOM или изменяет его, вы могли изменять состояние связанного наблюдаемого

Таким образом, по замыслу, инициализация вызывается только один раз для настройки привязки. Цель состоит в том, чтобы настроить объект DOM так, чтобы метод обновления работал правильно.