问题
I am attempting to use knockout-kendo.js to declare a kendo dropdownlist control in a knockout forEach template, so that as new items are added to the knockout observable array, new kendo dropdownlists are rendered in the UI.
Initially, I come to realize that I can no longer bind the dropdownlist's selected value to an entire entry object in my dropdownlist's specified 'data' array.
To overcome this issue, I followed the RP Niemeyer's suggestion in the following thread: Set the binding of a dropdown in knockout to an object
Now, this all works. Great.
My issue is when attempting to add second drop down list to the template, who's data is bound to an array property on the object being returned from the computed observable... (I need to chain the drop down lists so that the first displays all Students, second displays all classes for the student that is currently selected in the first drop down list, third displays all test grades for the class that is currently selected in the second drop down list, etc....)
I created a fiddle based on RP Niemeyer's original fiddle to demonstrate my issue:
Original Fiddle (RP Niemeyer's)
My Fiddle With Issues
I added the below lines to the fiddle:
HTML:
<input data-bind="kendoDropDownList: { dataTextField: 'caption', dataValueField: 'id', data: selectedChoice().shapes, value: selectedShapeId }" />
JS:
this.choices = ko.observableArray([
{ id: "1", name: "apple", shapes: ko.observableArray([ { id: "5", caption: "circle" }, { id: "6", caption: "square" }]) },
{ id: "2", name: "orange", shapes: ko.observableArray([ { id: "5", caption: "circle" }]) },
{ id: "3", name: "banana", shapes: ko.observableArray([ { id: "5", caption: "circle" }, { id: "6", caption: "square" }, { id: "7", caption: "triangle" }]) }
]);
Again, I was expecting that upon the selection changing in the first drop down list (causing selectedId to change, causing selectedChoice to change) would also cause any UI elements bound to 'selectedChoice' or any of selectedChoices' properties, to have their bindings re-evaluated and UI respectively updated.
Am I missing something? Or is there a better way to achieve this 'chaining of drop down list' behavior (while still utilizing a knockout template and kendo drop down list control)?
回答1:
Let me offer you some advice. Try to avoid accessing properties of an observable's value, as you can see, the dependency detection will not always be able to detect the dependency. You should create a computed observable which does the accessing for you.
var ViewModel = function () {
// ...
this.selectedChoice = ko.computed(function () {
var id = this.selectedId();
return ko.utils.arrayFirst(this.choices(), function(choice) {
return choice.id === id;
});
}, this);
this.selectedChoiceShapes = ko.computed(function () {
var selectedChoice = this.selectedChoice();
return selectedChoice && selectedChoice.shapes;
}, this);
}
Then your bindings becomes:
<input data-bind="kendoDropDownList: {
dataTextField: 'name',
dataValueField: 'id',
data: choices,
value: selectedId }" />
<input data-bind="kendoDropDownList: {
dataTextField: 'caption',
dataValueField: 'id',
data: selectedChoiceShapes,
value: selectedShapeId }" />
updated fiddle
回答2:
This appears to be a shortcoming of Kendo using Knockout. When Kendo evaluates selectedChoice().shapes
it holds onto the array it finds, instead of keeping the entire expression. If you update that specific array with options, you can see them in the second dropdown. The problem is that when you update selectedChoice
Kendo does not reevaluate the data to the new shapes
array. You can see this behavior in this fiddle.
Open the JS console, set the context to the fiddle (it defaults to the top frame
in Chrome`, and run this:
window.vm.choices()[1].shapes.push({"id": "6", "caption" : "Thing"})
And you will see the second dropdown update. Changing the first dropdown doesn't have an effect. You can see that in this fiddle Knockout without kendo reevaluates the entire expression, properly updating the second select
options.
来源:https://stackoverflow.com/questions/15640921/knockout-kendo-issues-binding-through-computed-observable