Подтвердить что ты не робот

Каков предпочтительный способ сохранения состояния между init и update для пользовательской привязки нокаута?

В настоящее время я сохраняю состояние, используя данные jQuery для элемента dom.

ko.bindingHandlers.customValue = {

    init: function init(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
        var state = { isEditing: false };        
        $(element).focus(function focus() {
            state.isEditing = true;
        }).blur(function blur() {
            state.isEditing = false;            
        }).data("customBinding", state);

    },

    update: function update(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
        // ignore if updating
        if (!$(element).data("customBinding").isEditing) {
            // handle update if they are not updating                                
        }
    }

};​

Есть ли лучшее место для хранения состояния для привязки, которое не требует dom? Может ли bindingContext использоваться для хранения состояния для каждого экземпляра привязки?

4b9b3361

Ответ 1

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

На самом деле существует два варианта сохранения состояния этого типа:

1- На элементе, как вы заявили. Вы можете использовать jQuery $.data, или KO включает API для этого, а также ko.utils.domData.get(element, key) и ko.utils.domData.set(element, key, value).

2- Поместите этот тип информации в свою модель просмотра, если это необходимо. Флаг для обозначения isEditing не обязательно неуместен в модели представления. Я лично хотел бы поместить этот тип "метаданных" в качестве суб-наблюдаемых с наблюдаемого типа:

var name = ko.observable("Bob");
name.isEditing = ko.observable(false);

Вы могли бы привязываться к name и name.isEditing.

Это имеет некоторые преимущества:

  • сохраняет модель обзора довольно чистой, так как вы не вводите новые свойства верхнего уровня.
  • сохраняет суб-наблюдаемое привязанное к родительскому наблюдаемому (нет необходимости в nameIsEditing и т.д.)
  • когда он превращается в JSON с чем-то вроде ko.toJSON, суб-наблюдаемый isEditing будет просто удален при распаковке родителя. Таким образом, вы не будете отправлять ненужные значения обратно на сервер.
  • в этом случае он также может иметь преимущество в том, что он доступен для других вычислений в вашей модели просмотра или для привязки к нескольким элементам вашего пользовательского интерфейса.

Ответ 2

Прикрепление данных к элементу прекрасно, и Knockout использует этот метод для привязки потока управления (если, с и т.д.), например.

Другим методом является использование функции init и использование вычисленного наблюдаемого для обработки обновлений. Я использую этот метод в привязке repeat. Вот важные части:

ko.bindingHandlers['repeat'] = {
    'init': function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
        ...
        // set up persistent data
        var lastRepeatCount = 0;
        ...
        ko.computed(function() {
            var repeatCount = ko.utils.unwrapObservable(valueAccessor());
            ...
            // Remove nodes from end if array is shorter
            for (; lastRepeatCount > repeatCount; lastRepeatCount--) {
                ...
            }
            ...
            // Add nodes to end if array is longer (also initially populates nodes)
            for (; lastRepeatCount < repeatCount; lastRepeatCount++) {
                ...
            }
        }, null, {'disposeWhenNodeIsRemoved': placeholder});
        ...
    }
};

Ответ 3

Я часто использую этот шаблон:

define(['knockout'], function(ko) {
  var interInstanceVariable = null;

  function Tree(element) {
    var privateInstanceVariable = null;

    function privateInstanceMethod() {}

    this.publicInstanceMethod = function() {}
  }


  ko.bindingHandlers.cannDendrogram = {
    init: function(element, valueAccessor) {
      $(element).data('tree', new Tree(element));
    },
    update: function(element, valueAccessor) {
      var tree = $(element).data('tree');
      tree.publicMethod();
    }
  };
});

Ответ 4

Я понимаю, что этот вопрос старый, но я наткнулся на него, ища подход, поэтому подумал, что я придумаю более современный метод ko.

Вы можете просто добавить свойства к bindingContext. $data напрямую. Я выбрал раздражающее имя переменной "___IsEditing", чтобы избежать потенциальных столкновений, но вы получаете идею...

ko.bindingHandlers.customValue = {

init: function init(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
    bindingContext.$data.___IsEditing = false;        
    $(element).focus(function focus() {
        bindingContext.$data.___IsEditing = true;
    }).blur(function blur() {
        bindingContext.$data.___IsEditing = false;            
    }).data("customBinding", state);

},

update: function update(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
    // ignore if updating
    if (bindingContext.$data.___IsEditing) {
        // handle update if they are not updating                                
    }
}

};

Ответ 5

Я использую функцию для создания общей области для init и update, определяя общие данные внутри функции.