starmucks starmucks - 10 days ago 6
jQuery Question

Knockout three cascading dropdowns

I really liked the live example in cartEditor. This is what I need. Well, almost what if I want to add another dropdown. For example if I want to add to an existing example another field

country
. The scenario is the following: I select the country, vehicle category and according to this choose the vehicle itself. How to bind two dropdowns to a third?

Tables in the database about such:

Table vehicle

id name countryId categoryId

Table category

id name

Table country

id name

File for a live example is located at knockoutjs.com

Answer

My solution is as follows. I wanted to filter based on ID. Plan to get the lists of countries and categories from the server and then receive from the server a filtered list of products. A huge thank you to the user. With Your help and with the help of the example on the website http://knockoutjs.com/examples/cartEditor.html I solved my problem. Post here my solution:

var countries = [
    {
        "id": 1,
        "name": "Russia"
    },
    {
        "id": 2,
        "name": "USA"
    },
    {
        "id": 3,
        "name": "Great Britain"
    }
];

var categories = [
    {
        "id": 1,
        "name": "Classic Cars"
    },
    {
        "id": 2,
        "name": "Motorcycles"
    },
    {
        "id": 3,
        "name": "Planes"
    }
];

var products = [
    {
        "name": "P-51-D Mustang",
        "countryId": 2,
        "categoryId": 3,
        "price": 12.42
    },
    {
        "name": "1997 BMW R 1100 S",
        "countryId": 2,
        "categoryId": 2,
        "price": 60.87
    },
    {
        "name": "2002 Chevy Corvette",
        "countryId": 2,
        "categoryId": 1,
        "price": 100.87
    },
    {
        "name": "1998 Chrysler Plymouth Prowler",
        "countryId": 1,
        "categoryId": 1,
        "price": 150.87
    }
];

var CartLine = function () {
    var self = this;
    self.countries = ko.observableArray(countries);
    self.categories = ko.observableArray(categories);
    self.quantity = ko.observable(1);
    self.selectedCountry = ko.observable();
    self.selectedCategory = ko.observable();
    self.selectedProduct = ko.observable();
    self.subtotal = ko.pureComputed(function () {
        return self.selectedProduct() ? (self.selectedProduct().price * self.quantity()) : "yet";
    });
    self.products = ko.pureComputed(function () {
        return $.grep(products, function (item) {
            return (self.selectedCountry() && self.selectedCategory() && item.countryId === self.selectedCountry().id && item.categoryId === self.selectedCategory().id);
        });
    });
};

var Cart = function () {
    var self = this;
    self.lines = ko.observableArray([new CartLine()]);
    self.lines2 = ko.observableArray([new CartLine()]);
    self.grandTotal = ko.pureComputed(function () {
        var total = 0;
        $.each(self.lines(), function () {
            total += this.subtotal();
        });
        return total;
    });

    // Operations
    self.addLine = function () {
        self.lines.push(new CartLine());
    };
    self.removeLine = function (line) {
        self.lines.remove(line);
    };
};

ko.applyBindings(new Cart());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<!DOCTYPE html>
<html>
    <head>
        <title>TODO supply a title</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <link rel="stylesheet" href="stl.css" />
    </head>
    <body>
            <div class='liveExample'>
                <table width='50%'>
                    <thead>
                        <tr>
                            <th width='25%'>Country</th>
                            <th width='25%'>Category</th>
                            <th class='price' width='15%'>Product</th>
                            <th class='price' width='15%'>Price</th>
                            <th class='quantity' width='10%'>Quantity</th>
                            <th class='price' width='15%'>Subtotal</th>
                            <th width='10%'></th>
                        </tr>
                    </thead>
                    <tbody data-bind='foreach: lines'>
                        <tr>
                            <td>
                                <select data-bind='options: countries, optionsText: "name", optionsCaption: "Select...", value: selectedCountry'> </select>
                            </td>
                            <td>
                                <select data-bind='options: categories, optionsText: "name", optionsCaption: "Select...", value: selectedCategory'> </select>
                            </td>
                            <td>
                                <select data-bind='visible: (selectedCountry() && selectedCategory()), options: products, optionsText: "name", optionsCaption: "Select...", value: selectedProduct'> </select>    
                            </td>
                            <td>
                                <span data-bind='text: selectedProduct() ? selectedProduct().price : 0'> </span>
                            </td>
                            <td class='quantity'>
                                <input data-bind='value: quantity, valueUpdate: "afterkeydown"' />
                            </td>
                            <td class='price'>
                                <span data-bind='text: subtotal()'> </span>
                            </td>
                            <td>
                                <a href='#' data-bind='click: $root.removeLine'>Remove</a>
                            </td>
                        </tr>
                    </tbody>
                </table>
                <p class='grandTotal'>
                    Total value: <span data-bind='text: grandTotal()'> </span>
                </p>
                <button data-bind='click: addLine'>Add product</button>
            </div>
        <script src="knockout-3.4.1.js" type="text/javascript"></script>
        <script src="jquery-3.1.1.min.js" type="text/javascript"></script>
        <script src="app.js" type="text/javascript"></script>
    </body>
</html>