I'm trying to write my KO templates in a certain manner, and it seems to be causing issues with Knockout, which stops updating the view. I wish to avoid too many explicit dependencies in my views as possible, so when I'm writing a template for adding to an files attachments list, I thought I could make use of the $data
variable:
<script id="attachments-template" type="text/html">
<input type="button" data-bind="attachments: $data" value="add">
</script>
And the template binding:
<div data-bind="template: {name: 'button-add-data', data: attachments}"></div>
This keeps the actual property mapped in the usage site, instead of off in random templates. The attachments
binding handler in my actual case wraps the jQuery fileupload plugin, but just calling push(i++)
shows the issue anyway.
var i = 0;
ko.bindingHandlers.attachments = {
init: function(element, valueAccessor) {
var files = valueAccessor();
$(element).click(function() {
files.push(i++);
});
}
};
var list = ko.observableArray();
var model= {
attachments: list
};
A fiddle which shows this, using KO 2.2.0: http://jsfiddle.net/stofte/sWGkJ/ The fiddle also shows that binding against an explicit property works fine.
Obviously there's alot of stuff on Google and SO on KO and binding contexts, but I can't find anything on the usage of $data in binding handlers, I'm not sure what KO law I'm breaking with my usage of $data, but seems like it would make good sense to be able to do what I want?
It appears that knockout doesn't eaxactly expect you to pass an observableArray
into the data
paramater on a template binding. Usually that's what a foreach
is for. It seems that data
expects a regular object to behave correctly (citation needed, couldn't find any docs other than the fact that it appears to behave this way).
Using the same JS code that you have, the easiest solution seems like it would be to wrap the observable array straight in your template binding:
<script id="button-add-data" type="text/html">
isObservable: <span data-bind="text: ko.isObservable(items)"></span><br>
toJSON: <span data-bind="text: ko.toJSON(items)"></span><br>
<input type="button" data-bind="attachments: items" value="doesnt update">
</script>
<div data-bind="template: {name: 'button-add-data', data: { items: attachments }}"></div>
Alternatively you could override your template bindingHandler and create a new parameter you can pass in which simplifies this similar behaviour. Link: knockoutjs overriding bindinghandlers
If 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