Reputation: 24315
I just upgraded to knockout.js 2.2.0 and a foreach statement isnt working anymore with a computed observable. If I switched back to 2.1 it works. The computed observable updatedValues
doesnt repopulate the foreach
in the html below. Keep in mind the html below is dynamically inserted into the dom on a single ajax page and applied bindings.
ko.bindingHandlers.fields = {
init: function (element, valueAccessor) {
var value = ko.utils.unwrapObservable(valueAccessor());
app.viewModel.members.meta = {
values: ko.observableArray(value.values),
remove: function () {
app.viewModel.members.meta.values.remove(this);
return false;
},
add: function () {
app.viewModel.members.meta.values.push({ Name: '', Value: '', Index: ko.observable(app.viewModel.members.meta.values().length) });
return false;
},
max: value.max
};
app.viewModel.members.meta.updatedValues = ko.computed(function () {
if (this.values()) {
for (var i = 0; i < this.values().length; i++) {
if (this.values()[i].Index)
this.values()[i].Index(i);
else
this.values()[i].Index = ko.observable(i);
}
}
return this.values;
}, app.viewModel.members.meta);
}
};
<div class="control-group">
@Html.LabelFor(q => q, "Custom Fields")
<div class="controls">
<div class="meta" data-bind="fields: { values: @Model.Meta.OrderBy(q => q.Name).ToJSON(), max: @Model.MaxCount }">
<div data-bind="foreach: members.meta.updatedValues">
<div class="form-inline">
<div class="input-prepend">
<span class="add-on">Name</span>
@Html.TextBox("Key", string.Empty, new { maxvalue = "100", data_bind = "value: Name, attr: { name: '" + Model.PropertyName + "[' + Index() + '].Name', id: '" + Model.PropertyName + "[' + Index() + '].Name' }" })
</div>
@if(!Model.HideValues)
{
<div class="input-prepend">
<span class="add-on">Value</span>
@Html.TextBox("Value", string.Empty, new {data_bind = "value: Value, attr: { name: '" + Model.PropertyName + "[' + Index() + '].Value', id: '" + Model.PropertyName + "[' + Index() + '].Value' }"})
</div>
}
<a href="#" class="btn btn-mini btn-danger" title="Remove Field" data-bind="click: $parent.members.meta.remove"><i class="icon-minus icon-white"></i></a>
</div>
</div>
<div class="control-group">
@Html.Button("New Field", new { type="button", @class="btn", data_bind = "click: members.meta.add, visible: members.meta.max >= members.meta.values().length" })
@Html.Partial(MVC.Shared.Views.Controls.Help, new HelpModel { Url = Url.Action(Model.ActionResult ?? MVC.Members.Dashboard.CustomFieldsHelp()), Title = Model.Title ?? "Custom Fields" })
</div>
</div>
</div>
</div>
Upvotes: 1
Views: 1255
Reputation: 13371
Have a look about the updates done here Knockout 2.2.0 released.
foreach and template enhancements
When a function is used for the template name, it now receives the binding context as the second argument.
The foreach functionality now does its best to understand items that were moved and move their content rather than re-render them.
beforeMove and afterMove callbacks can now be configured when using foreach functionality.
The foreach and template bindings now accept an as option to give $data an alias.
The afterRender, beforeRemove, afterAdd, beforeMove, and afterMove callbacks will no longer cause dependencies.
I think that computed should be returning a plain array so change it to values: []
because in Knockout 2.2 there is no twice-unwraping of the observables when using foreach()
.
You can always log an issue here: https://github.com/SteveSanderson/knockout/issues
Upvotes: 2