Reputation: 6152
I followed the Knockout tutorials some time ago of which one of them http://learn.knockoutjs.com/#/?tutorial=collections
details how to creating lists and collections. However I want to create a cascading drop down select within the list.
My question would have been can you create a cascading drop down in a dynamic list like this using knockout?
As it happens I've actually managed to solve the question after a couple of hours of looking into it so will add it here as an answer as I think it could be useful for someone. Maybe there are better ways of doing it?
Upvotes: 2
Views: 4753
Reputation: 9274
It would work, but I would just add one thing: small caching. Basically, once you've loaded the meals available for a given meal you could create a property in your meal object to store them. That way, subsequent calls may know that these meals have already been loaded. I've created an observable array for that, like so:
Given this function which simulates retrieving data from the server:
var mealTypesByKey = [];
mealTypesByKey[1] = [{ mealName: "Vegemite Sandwich", price: 4.00, mealType: 1},
{ mealName: "Cheese Sandwich", price: 34.95,mealType: 2 },
{ mealName: "Jam Sandwich", price: 290, mealType: 3 } ];
mealTypesByKey[2] = [{ mealName: "Standard (Ham)", price: 15, mealType: 1},
{ mealName: "Chicken Wrap (Possibly rat)", price: 15, mealType: 1} ];
mealTypesByKey[3] = [{ mealName: "Premium (lobster)", price: 34.95,mealType: 2 },
{ mealName: "Ultimate (whole zebra)", price: 290, mealType: 3 } ];
function serverGetMealsForType(key) {
return mealTypesByKey[key];
}
You can define the following subscribable function:
self.mealType.subscribe(function(newMealType) {
if(!newMealType.meals) {
newMealType.meals = ko.observableArray([]);
newMealType.meals(serverGetMealsForType(newMealType.key));
console.log("meals loaded");
} else {
console.log("meals already available for meal type " + newMealType.key);
}
});
And that way, the dynamic list is recreated properly with the given binding:
<td><select data-bind="options: mealType().meals, value: meal, optionsText: 'mealName'"></select></td>
This is a common and easy technique to avoid unneeded server calls.
Edit: forgot to add the fiddle I've forked.
Upvotes: 2
Reputation: 6152
I took the original version of the collections tutorial from learn.knockoutjs.com. I decided to add a meal types selection which change the available meals when selected.
I discovered that the available meals needed to move into the individual list items as it was going to change each
function SeatReservation(name, initialMeal, initialMealType) {
var self = this;
self.name = name;
self.meal = ko.observable(initialMeal);
// Non-editable catalog data - would come from the server
self.availableMeals = ko.observableArray([
{ mealName: "Standard (sandwich)", price: 0, mealType: 1},
{ mealName: "Premium (lobster)", price: 34.95,mealType: 2 },
{ mealName: "Ultimate (whole zebra)", price: 290, mealType: 3 }
]);
I created a meal type also within the individual booking:
self.mealType= ko.observable();
Then a list of available meal types:
// Non-editable catalog data - would come from the server
self.availableMealTypes = [
{ mealTypeName: "Vege", key: 1 },
{ mealTypeName: "Dead Animal", key: 2 },
{ mealTypeName: "Meat Whore", key: 3}
];
Which was then bound to in the HTML.
Finally I subscribed to the change in the meal type and modified the available meals collection in this function:
self.mealType.subscribe(function() {
if (self.mealType().key == 1)
{
self.availableMeals ([
{ mealName: "Vegemite Sandwich", price: 4.00, mealType: 1},
{ mealName: "Cheese Sandwich", price: 34.95,mealType: 2 },
{ mealName: "Jam Sandwich", price: 290, mealType: 3 } ]);
}
The final and complete solution can be seen in this jsFiddle.
Upvotes: 1