Question

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?

Was it helpful?

Solution

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.

OTHER TIPS

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top