Custom Binding - init продолжает вызываться

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

Если появится новый предмет, скажем E Я хотел бы, чтобы он был включен. Мне также нужно обновлять зеленый штрих вокруг каждого круга каждый раз, когда меняется привязка.

Моя проблема в том, что когда мой context связывание обновлений в приведенном ниже коде, что вся привязка, кажется, переинициализируется. Я думаю, что Knockout под ним удаляет DOM для предыдущего context и повторно рендерит весь лот - это вызывает рост каждого круга и запускает анимацию нового элемента.

ko.components.register("context", {
    // Assume that the view model given to us is already observable, having had a ko.mapping.fromJS() applied or similar
    viewModel: function (vm) {
        this.context = vm;
    },
    template: '<div class="card context-card" data-bind="contextViz: context">\
                <!-- ko if: context && context.types.length === 0 -->\
                    <div>Please make a selection to view contextual information here.</div>\
                <!-- /ko -->\
               </div>\
               '
});

Мне интересно, могу ли я что-нибудь сделать, чтобы предотвратить это. По сути хочу старый context привязка просто обновить, но я не уверен, есть ли способ сделать это.

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

var count = 0;

ko.bindingHandlers.contextViz = {
    init: function() {
        console.log("init called");
    },
    update: function() {
        console.log("update called");
    }
};

ko.components.register("context", {
    viewModel: function (vm) {
        this.context = vm;
    },
    template: '<div class="card context-card" data-bind="contextViz: context">'
});

var vm = {
   context: ko.observable({ count: count })
};

ko.applyBindings(vm);

setInterval(function() {
  vm.context({ count: count + 1 });  
}, 1000);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<div data-bind="component: { name: 'context', params: $root.context }"></div>

1 ответ

Решение

Потому что вы напрямую используете свой context собственность как params вашего вычисленного нокаутом будет заново визуализировать весь вычисленный, когда context изменения.

Обычная практика - передавать объект с некоторыми свойствами в качестве params поэтому при изменении свойств этого объекта компонент не полностью перерисовывается.

Так что вам нужно изменить свой HTMl на:

<div data-bind="component: { name: 'context', params: { context: $root.context }}"></div>

А в вашем вычисленном конструкторе просто напишите:

viewModel: function (params) {
    this.context = params.context;
},

var count = 0;

ko.bindingHandlers.contextViz = {
init: function() {
    document.getElementById("log").innerHTML += "init called\n";
},
update: function(e,v) {
    console.log(ko.unwrap(v())) // make a dependency so it will be called when the bound observable changes
    document.getElementById("log").innerHTML += "update called\n";
}
};

ko.components.register("context", {
viewModel: function (params) {
    this.context = params.context;
},
template: '<div class="card context-card" data-bind="contextViz: context">'
});

var vm = {
   context: ko.observable({ count: count })
};

ko.applyBindings(vm);

setInterval(function() {
  vm.context({ count: ++count });  
}, 1000);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<div data-bind="component: { name: 'context', params: { context: $root.context }}"></div>
<div>log:</div>
<pre id="log"></pre>

Другие вопросы по тегам