I've been trying to use both a custom component, and then a custom binding within Knockout to render a small visualization. I got this working, but realized the solution wasn't ideal. My custom binding is supposed to handle changes to the data by using transitions.
If a new item appears, say E
, I'd like it to transition in. I also need to update the green stroke round each circle everytime the binding changes.
My issue is that when my context
binding updates in the code below, that the whole binding seems to re-initialize. I think Knockout underneath is removing the DOM for the previous context
and re-renders the entire lot - this causes each circle to grow and triggers the new item animation.
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>\
'
});
I'm wondering if there's anything I can do to prevent this. Essentially I want the old context
binding to just update but I'm not sure if there's a way to do so.
I've added a code snippet to illustrate. Here init called
is logged each time an update occurs, I only want this to log once, and update called
to be logged many times.
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>