问题
I have 2 observabeleArrays. One contains all the possible types which I can select and the other one contains all the selected ones. The first template shows all the possible types and the other all the selected ones. If I click on one of first template(all possibilities), it gets added to the list of selected ones and is displayed in the second template. If I click on a selected one in the second template it is removed from there. Also, in the first template I want to display a check on the objects that are selected. Most of the stuff works, except the check does not get updated if I remove an object via the second template. I've tried to reduce my code to the important parts, I hope it makes more sense like this and doesn't have any mistakes: Anyone an idea how to fix it, so my check shows correctly? It's depending on the Selected value of each object, which updates correctly, but the view doesn't change.
//main html
//...
<div data-bind="component: {
name: 'selector-component',
params: {
selected: vm.selected,
types: vm.types,
}
}">
</div>
<div data-bind="component: {
name: 'selected-component',
params: {
selected: vm.selected,
}
}">
</div>
//...
<script type="text/javascript">
vm.selected = ko.observableArray([]);
vm.types = ko.observableArray([]);
ko.components.register('model-selected-component', {
template: { element: document.getElementById('selector-component-template') },
viewModel: SelectorComponentModel
});
</script>
<script type="text/javascript">
vm.selected = ko.observableArray([]);
ko.components.register('model-selected-component', {
template: { element: document.getElementById('selected-component-template') },
viewModel: SelectorComponentModel
});
</script>
//template1
<template id="selector-component-template">
<div class="panelContainer">
<!-- ko foreach: types -->
<a data-bind="attr: {title: Name}, click: $parents.select" class="thumbnail text-center" href="#">
<span style="display:block;height:10px;width:10px;">
<i data-bind="visible: Selected" class="fa fa-check" style="color:green"></i>
<img src="@Url.Content("~/Content/Images/type.png")" />
</span>
</a>
<!-- /ko -->
</div>
</template>
//template2
<template id="selected-component-template">
<div class="panel panel-default">
<div class="panel-heading">Selected Properties</div>
<div class="panel-body">
<div class="panel-body panel-body-nobottompadding">
<div class="panelContainer">
<!-- ko foreach: selected -->
<a class="thumbnail text-center" data-bind="attr: {title: Name}, click: $parent.select">
<img src="@Url.Content("~/Content/Images/type.png")" />
</a>
<!-- /ko -->
</div>
</div>
</div>
</template>
//selector.js
function SelectorComponentModel(params) {
var self = this;
self.selected = params.selected || ko.observableArray([]);
self.types = params.types || ko.observableArray([]);
self.select = function (types) {
if (self.selected.indexOf(types) == -1)
self.selected.push(types);
else
self.selected.remove(types);
types.Selected = types.Selected == true ? false : true;
//refresh
var data = self.types();
self.types([]);
self.types(data);
}
回答1:
You should not try to maintain two separate arrays. Just make one array for all items and computed array for selected items only.
self.items = ko.observableArray();
self.items.selected = ko.computed(() => {
return self.items().filter(item => item.selected());
});
Take a look at this example.
Update
As you may see I use arrow functions alot. However they are part of ES6 standard supported by most modern browsers your experience may differ. For such unlucky users there is more classic example.
Update 2
Of course your Selected property must be observable. You can convert this property for each item before assigning to the model.
Updated example
来源:https://stackoverflow.com/questions/41161828/knockout-observablearray-in-2-templates