I am trying to use a custom bindingHandler that adds something like a template and so needs its own model. Just for information (but not required to understand the problem): the real goal is to manage several components that are located inside the DIV that has this bindingHandler.
However, I am unable to create a custom context BUT keep KO from trying to bind the elements I created (and already applied binding on it with the custom bindingHandler).
All I get is the typical error: Uncaught Error: You cannot apply bindings multiple times to the same element.
What I guess is that:
Knockout is doing the first applyBinding and search for the binding handlers on elements within it
It does the initialization process of it
The initialization create a new context with the applyBindings on new elements
After the completion of that operation, knockout seems to not take into account "allowBindings:false" on created elements (and elements that are already bound) and try to bind twice the things...
http://jsfiddle.net/darknessm0404/tB6Zv/3/
<div id="view">
viewModel content.
<p data-bind="text:data"></p>
<div data-bind="customComponent:{}">
<p>Need to have is own model. Another element is added while the constructor of the viewModel is instancied.</p>
</div>
</div>
ko.bindingHandlers.allowBindings = {
init: function (elem, valueAccessor) {
// Let bindings proceed as normal *only if* my value is false
var shouldAllowBindings = ko.unwrap(valueAccessor());
return { controlsDescendantBindings: !shouldAllowBindings };
}
};
ko.bindingHandlers.customComponent = {
init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
// Append new element
var $component = $('<div data-bind="allowBindings:false">customComponent content: <span data="text:data"></span><div>').appendTo($(element));
// Apply bindings on newly created element
console.log('2.A. customComponent -> applyBindings -> started');
ko.applyBindings({
data: 'COMPONENT MODEL DATA'
}, $component[0]);
console.log('2.A. customComponent -> applyBindings -> completed');
}
};
console.log('1.A. view -> applyBindings -> started');
ko.applyBindings({
data: 'VIEW MODEL DATA'
}, $('#view')[0]);
console.log('1.B. view -> applyBindings -> completed');
How to force knockout to NOT parse these items that are already bound? I tried to add allowBindings:false to the DIV containing the "customComponent:...", it still initializes but I'm not able to get the model.data property out of it.
Here's a part of the code I've used. I simply had forgotten to add return { controlsDescendantBindings: true }; to prevent KO to apply bindings on the created children elements.
It may not compile directly but the idea is the same: binding a new childContext on a new element created by the binding, and initializing siblings of that item with the current binding context.
With that, I'm able to manage components within a group (div), these components can access to the parent model (code not shown here, it's done via $.closest and storing things with $.data) and so ask themselves to be appended to the "panel.list" referred by the template.
init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
//...
// Template creation
var $template = $('<ul></ul>').prependTo($(element));
Quadratus.ko.dataBind($template, {
foreach: 'panel.list'
});
$('<li><span data-bind="text:\'hello\'"></span></li>').appendTo($template);
ko.applyBindings(bindingContext.createChildContext(model), $template[0]);
$template.siblings().each(function () {
// Apply current bindingcontext on siblings
ko.applyBindings(bindingContext, this);
});
return { controlsDescendantBindings: true };
Return { controlsDescendantBindings: true } from your customComponent init function.
See http://knockoutjs.com/documentation/custom-bindings-controlling-descendant-bindings.html
Here is an update to your fiddle: http://jsfiddle.net/tB6Zv/4/
Besides adding the controlsDescendantBindings return value, I also made these changes:
allowBindings: falsedata="text: data" which should have been data-bind="text: data"ko.applyBindings for the new elements to ko.applyBindingsToDescendants, which is more commonly used in this situationIf you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With