knockout.js 基于其他observable knockoutjs更新observableArray

2q5ifsrm  于 7个月前  发布在  其他
关注(0)|答案(1)|浏览(75)

每次使用单独的选择框时,我都需要更新一个observableArray。问题是酵母.如果用户选择“Danstar”作为酵母的类别,“酵母品种”现在应该只显示

Danstar
  Danstar 1
  Danstar 2

其中“Danstar”是选项组。我的想法是

{category: 'Danstar', yeasts: ['Danstar 1', 'Danstar 2']}

并设置为yeast_groups_individual。我需要每对“酵母品牌过滤器”和“酵母品种”独立运作。到目前为止我有:

ko.observableArray.fn.countVisible = function(){
            return ko.computed(function(){
                var items = this();

                if (items === undefined || items.length === undefined){
                    return 0;
                }

                var visibleCount = 0;

                for (var index = 0; index < items.length; index++){
                    if (items[index]._destroy != true){
                        visibleCount++;
                    }
                }

                return visibleCount;
            }, this)();
        };

        function Hop(data) {
            this.name = ko.observable(data.name || "");
            this.amount = ko.observable(data.amount || "");
            this.time = ko.observable(data.time || "");
            this.use = ko.observable(data.use || "Boil");
        }

        function Fermentable(data) {
            this.name = ko.observable(data.name || "");
            this.pounds = ko.observable(data.pounds || "");
            this.ounces = ko.observable(data.ounces || "");
            this.weight_unit = ko.observable(data.weight_unit || "oz");
            this.milling_preference = ko.observable(data.milling_preference || "Milled");
        }

        function Yeast(data){
            var self = this;
            self.name = ko.observable(data.name || "White Wine");
            self.current_filter = ko.observable("-Any-");
            var yeast_options = [
                {category: 'Danstar', yeasts: ['Danstar 1', 'Danstar 2']},
                {category: 'Fermentis', yeasts: ['West Coast', 'American Saison', 'White Wine']},
                {category: 'White Labs', yeasts: ['White 1', 'White Saison']},
            ];
            self.yeast_groups_individual = ko.observableArray();
            ko.computed(function(){
                if (self.current_filter() !== "-Any-"){
                    var options = _.filter(yeast_options, function(option){
                        return option.category === self.current_filter();
                    })
                } else{
                        self.yeast_groups_individual(yeast_options);
                    }
                }
            );
            self.yeast_categories = ko.observableArray();
            ko.computed(function(){
                var starter_list = ['-Any-'];
                var categories = _.pluck(self.yeast_groups_individual(), 'category');
                var final = starter_list.concat(categories);
                self.yeast_categories(final);
            })
        }

        function TaskListViewModel() {
            var self = this;

            self.recipe_name = ko.observable("");
            self.hops = ko.observableArray([new Hop({}), new Hop({})]);
            self.fermentables = ko.observableArray([new Fermentable({name: 'test'}), new Fermentable({})]);
            self.yeasts = ko.observableArray([new Yeast({})]);
            self.hops_uses = ko.observableArray(['Boil', 'Dry Hop']);
            self.weight_units = ko.observableArray(['oz', 'lb']);
            self.milling_preferences = ko.observableArray(['Milled', 'Unmilled']);

            self.addFermentable = function(){
                self.fermentables.push(new Fermentable({}))
            }

            self.addYeast = function(){
                self.yeasts.push(new Yeast({}));
            }

            self.addHop = function(){
                self.hops.push(new Hop({}));
            }

            self.removeFermentable = function(fermentable){
                self.fermentables.destroy(fermentable);
            }

            self.removeYeast = function(yeast){
                self.yeasts.destroy(yeast);
            }

            self.removeHop = function(hop){
                self.hops.destroy(hop);
            }

            self.removeItem = function(item, name){
                name.remove(function(hop){
                    return hop.name === item.name;
                });
                console.log(name());
                console.log(self.hops());
            }

            self.prepareJSON = function(){
                object = {
                    fermentables: self.fermentables(),
                    hops: self.hops(),
                    yeasts: self.yeasts(),
                }
                return object
            }

            self.saveRecipeData = function(){
                var data_to_send = ko.toJSON(self);
                var recipe_data = ko.toJSON(self.prepareJSON());
                alert("This is the data you're sending (universal Javascript object notation):\n\n" + recipe_data)
                $.ajax({
                    url: "http://127.0.0.1:5000/receive-recipe",
                    headers: {
                        "Content-Type": "application/json"
                    },
                    method: "POST",
                    dataType: "json",
                    data: data_to_send,
                    success: function(data){
                        console.log("Success! Saved the recipe");
                    }
                });
            }
        }
        ko.applyBindings(new TaskListViewModel());
<style>
        .setuprow label {
            margin: 8px 0 0;
            display: block;
            clear: both;
        }
    </style>  
    <script type='text/javascript' src='https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.1/knockout-min.js'></script>
    <script type='text/javascript' src='https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js'></script>
    <script type='text/javascript' src='https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js'></script>
<div class="setuprow">
        <label>Recipe Name:</label>
        <input type="text" data-bind="value: recipe_name" maxlength="250" class="recipeSetupText" />
    </div>
    <div class="setuprow">
        <label>Brew Method:</label>
        <select class="recipeSetupSelect">
            <option value="extract" selected>Extract</option>
            <option value="partialmash">Mini-Mash</option>
            <option value="allgrain">All Grain</option>
            <option value="biab">Brew-in-a-bag</option>
        </select>
    </div>

    <div class="setuprow">
        <label>Batch Size:</label>
        <input type="text" value="5" maxlength="6" style="width: 60px" /> <span class="unit">(gallons)</span>
    </div>

    <div class="setuprow">
        <label>Style:</label>
        <select class="recipeSetupSelect">
            <option value="--">--</option>
            <option value="Standard American Beer">1. Standard American Beer</option>
            <option value="International Lager">2. International Lager</option>
            <option value="Czech Lager">3. Czech Lager</option>
            <option value="Pale Malty European Lager">4. Pale Malty European Lager</option>
            <option value="Pale Bitter European Beer">5. Pale Bitter European Beer</option>
            <option value="Amber Malty European Lager">6. Amber Malty European Lager</option>
            <option value="Amber Bitter European Lager">7. Amber Bitter European Lager</option>
            <option value="Dark European Lager">8. Dark European Lager</option>
        </select>
    </div>

    <div>
        <label>Boil Time:</label>
        <input type="text" value="60" maxlength="3" style="width: 60px" /> <span class="unit">(minutes)</span>
    </div>

    <div class="row">
        <h2>Fermentables</h2>
        <div data-bind="foreach: fermentables">
            <label>Name:</label>
            <input type="text" data-bind="value: name"/>
            <label>Amount:</label>
            <input style="width: 45px;" type="number" min="0" data-bind="value: pounds"/> lb
            <input style="width: 55px;" type="number" min="0" data-bind="value: ounces"/> oz
            <label>Milling preference: </label>
            <select data-bind="options: $root.milling_preferences, value: weight_unit">
            </select>
            <a href="#" data-bind="click: $root.removeFermentable, visible: $root.fermentables.countVisible() > 1">
                Delete
            </a>
            <br><br>
        </div>

        <input data-bind="click: addFermentable" type="button" value="Add Fermentable" />
    </div>

    <div class="row">
        <h2 class="">Yeast</h2>
        <div data-bind="foreach: yeasts">
            <span>Yeast Brand Filter:</span>
            <select data-bind="options: yeast_categories, value: current_filter" id="yeast-brand-select">
            </select>
            <br/>
            <span>Yeast Variety:</span>
            <select id="yeast-variety-select" style="width:325px" data-bind="value: name">
                <option value="-"> - </option>
                    <!-- ko foreach: yeast_groups_individual -->
                    <optgroup data-bind="attr: {label: category}">
                        <!-- ko foreach: yeasts -->
                            <option data-bind="value: $data, text: $data"></option>
                        <!-- /ko -->
                    </optgroup>
                <!-- /ko -->
            </select>
            <a href="#" data-bind="click: $root.removeYeast, visible: $root.yeasts.countVisible() > 1">Delete</a>
            <br><br>
        </div>
        <br>
        <input data-bind="click: addYeast" type="button" value="Add Yeast"/>
    </div>

    <div class="row">
        <h2 class="">Hops</h2>
        <div data-bind='foreach: hops'>
            <label>Hop:</label> <input type="text" data-bind="value: name" >
            <label>Amount:</label>
            <input type="number" data-bind="value: amount" maxlength="6"> oz

            Time: <input type="text" data-bind="value: time" >
            Min.
            Use:  <select data-bind="options: $root.hops_uses, value: use"></select>

            <a href="#" data-bind="click: function() { $root.removeItem($data, $root.hops) }, visible: $root.hops.countVisible() > 1">Delete</a>

            <br><br>
        </div>

        <br>

        <input data-bind="click: addHop" type="button" value="Add Hop" />
    </div>

    <p>
        <button data-bind="click: saveRecipeData">Save recipe</button>
    </p>

current_filter被改变时,如何使yeast_groups_individual可观察数组更新?

2ekbmq32

2ekbmq321#

到目前为止,我找到的最好的答案是将主数组永久连接到ViewModel,并将其副本(yeast_options)传递给每个酵母,现在它可以在不破坏其他酵母行为的情况下使用该数组:

ko.observableArray.fn.countVisible = function(){
            return ko.computed(function(){
                var items = this();

                if (items === undefined || items.length === undefined){
                    return 0;
                }

                var visibleCount = 0;

                for (var index = 0; index < items.length; index++){
                    if (items[index]._destroy != true){
                        visibleCount++;
                    }
                }

                return visibleCount;
            }, this)();
        };

        function Hop(data) {
            this.name = ko.observable(data.name || "");
            this.amount = ko.observable(data.amount || "");
            this.time = ko.observable(data.time || "");
            this.use = ko.observable(data.use || "Boil");
        }

        function Fermentable(data) {
            this.name = ko.observable(data.name || "");
            this.pounds = ko.observable(data.pounds || "");
            this.ounces = ko.observable(data.ounces || "");
            this.weight_unit = ko.observable(data.weight_unit || "oz");
            this.milling_preference = ko.observable(data.milling_preference || "Milled");
        }

        function Yeast(data){
            var self = this;
            var permanent_yeast_options = data.yeast_options;
            self.name = ko.observable(data.name || "-");
            self.current_filter = ko.observable("-Any-");
            self.yeast_groups_individual = ko.computed(function(){
                if (self.current_filter() !== "-Any-"){
                    var options = _.filter(data.yeast_options, function(option){
                        return option.category === self.current_filter();
                    });
                    return options;
                } else{
                        return permanent_yeast_options;
                    }
                }
            );
            self.yeast_categories = ko.observableArray();
            ko.computed(function(){
                var starter_list = ['-Any-'];
                var categories = _.pluck(permanent_yeast_options, 'category');
                var final = starter_list.concat(categories);
                self.yeast_categories(final);
            })
        }

        function TaskListViewModel() {
            var self = this;
            self.hops_uses = ko.observableArray(['Boil', 'Dry Hop']);
            self.weight_units = ko.observableArray(['oz', 'lb']);
            self.milling_preferences = ko.observableArray(['Milled', 'Unmilled']);
            self.recipe_name = ko.observable("");
            self.hops = ko.observableArray([new Hop({}), new Hop({})]);
            self.fermentables = ko.observableArray([new Fermentable({name: 'test'}), new Fermentable({})]);
            self.yeast_options = [
                {category: 'Danstar', yeasts: ['Danstar 1', 'Danstar 2']},
                {category: 'Fermentis', yeasts: ['West Coast', 'American Saison', 'White Wine']},
                {category: 'White Labs', yeasts: ['White 1', 'White Saison']},
            ];
            self.yeasts = ko.observableArray([new Yeast({yeast_options: self.yeast_options})]);
            self.addFermentable = function(){
                self.fermentables.push(new Fermentable({}))
            }

            self.addYeast = function(){
                self.yeasts.push(new Yeast({yeast_options: self.yeast_options}));
            }

            self.addHop = function(){
                self.hops.push(new Hop({}));
            }

            self.removeFermentable = function(fermentable){
                self.fermentables.destroy(fermentable);
            }

            self.removeYeast = function(yeast){
                self.yeasts.destroy(yeast);
            }

            self.removeHop = function(hop){
                self.hops.destroy(hop);
            }

            self.removeItem = function(item, name){
                name.remove(function(hop){
                    return hop.name === item.name;
                });
                console.log(name());
                console.log(self.hops());
            }

            self.ingredient_filter = function(the_array){
                var options = _.filter(the_array, function(item){
                    return item.name != "" && item.name != "-";
                });
                return options;
            }

            self.prepareJSON = function(){
                object = {
                    fermentables: self.fermentables(),
                    hops: self.hops(),
                    yeasts: self.yeasts(),
                }
                return object
            }

            self.saveRecipeData = function(){
                var data_to_send = ko.toJSON(self);
                var recipe_data = ko.toJSON(self.prepareJSON());
                alert("This is the data you're sending (universal Javascript object notation):\n\n" + recipe_data)
                $.ajax({
                    url: "http://127.0.0.1:5000/receive-recipe",
                    headers: {
                        "Content-Type": "application/json"
                    },
                    method: "POST",
                    dataType: "json",
                    data: recipe_data,
                    success: function(data){
                        console.log("Success! Saved the recipe");
                    }
                });
            }
        }
        ko.applyBindings(new TaskListViewModel());
<head>

    <style>
        body {
            margin: 30px;
            padding: 30px;
        }
        .setuprow label {
            margin: 8px 0 0;
            display: block;
            clear: both;
        }
    </style>
    <script type='text/javascript' src='https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.1/knockout-min.js'></script>
    <script type='text/javascript' src='https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js'></script>
    <script type='text/javascript' src='https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js'></script>
    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>

</head>

<body>
    <div class="setuprow">
        <label>Recipe Name:</label>
        <input type="text" data-bind="value: recipe_name" maxlength="250" class="recipeSetupText" />
    </div>
    <div class="setuprow">
        <label>Brew Method:</label>
        <select class="recipeSetupSelect">
            <option value="extract" selected>Extract</option>
            <option value="partialmash">Mini-Mash</option>
            <option value="allgrain">All Grain</option>
            <option value="biab">Brew-in-a-bag</option>
        </select>
    </div>

    <div class="setuprow">
        <label>Batch Size:</label>
        <input type="text" value="5" maxlength="6" style="width: 60px" /> <span class="unit">(gallons)</span>
    </div>

    <div class="setuprow">
        <label>Style:</label>
        <select class="recipeSetupSelect">
            <option value="--">--</option>
            <option value="Standard American Beer">1. Standard American Beer</option>
            <option value="International Lager">2. International Lager</option>
            <option value="Czech Lager">3. Czech Lager</option>
            <option value="Pale Malty European Lager">4. Pale Malty European Lager</option>
            <option value="Pale Bitter European Beer">5. Pale Bitter European Beer</option>
            <option value="Amber Malty European Lager">6. Amber Malty European Lager</option>
            <option value="Amber Bitter European Lager">7. Amber Bitter European Lager</option>
            <option value="Dark European Lager">8. Dark European Lager</option>
        </select>
    </div>

    <div>
        <label>Boil Time:</label>
        <input type="text" value="60" maxlength="3" style="width: 60px" /> <span class="unit">(minutes)</span>
    </div>

    <div class="row">
        <h2>Fermentables</h2>
        <div data-bind="foreach: fermentables">
            <label>Name:</label>
            <input type="text" data-bind="value: name"/>
            <label>Amount:</label>
            <input style="width: 45px;" type="number" min="0" data-bind="value: pounds"/> lb
            <input style="width: 55px;" type="number" min="0" data-bind="value: ounces"/> oz
            <label>Milling preference: </label>
            <select data-bind="options: $root.milling_preferences, value: weight_unit">
            </select>
            <a href="#" data-bind="click: $root.removeFermentable, visible: $root.fermentables.countVisible() > 1">
                Delete
            </a>
            <br><br>
        </div>

        <input data-bind="click: addFermentable" type="button" value="Add Fermentable" />
    </div>

    <div class="row">
        <h2 class="">Yeast</h2>
        <div data-bind="foreach: yeasts">
            <span>Yeast Brand Filter:</span>
            <select data-bind="options: yeast_categories, value: current_filter" id="yeast-brand-select">
            </select>
            <br/>
            <span>Yeast Variety:</span>
            <select id="yeast-variety-select" style="width:325px" data-bind="value: name">
                <option value="-"> - </option>
                    <!-- ko foreach: yeast_groups_individual -->
                    <optgroup data-bind="attr: {label: category}">
                        <!-- ko foreach: yeasts -->
                            <option data-bind="value: $data, text: $data"></option>
                        <!-- /ko -->
                    </optgroup>
                <!-- /ko -->
            </select>
            <a href="#" data-bind="click: $root.removeYeast, visible: $root.yeasts.countVisible() > 1">Delete</a>
            <br><br>
        </div>
        <br>
        <input data-bind="click: addYeast" type="button" value="Add Yeast"/>
    </div>

    <div class="row">
        <h2 class="">Hops</h2>
        <div data-bind='foreach: hops'>
            <label>Hop:</label> <input type="text" data-bind="value: name" >
            <label>Amount:</label>
            <input type="number" data-bind="value: amount" maxlength="6"> oz

            Time: <input type="text" data-bind="value: time" >
            Min.
            Use:  <select data-bind="options: $root.hops_uses, value: use"></select>

            <a href="#" data-bind="click: function() { $root.removeItem($data, $root.hops) }, visible: $root.hops.countVisible() > 1">Delete</a>

            <br><br>
        </div>

        <br>

        <input data-bind="click: addHop" type="button" value="Add Hop" />
    </div>

    <p>
        <button data-bind="click: saveRecipeData">Save recipe</button>
    </p>

 
</body>

相关问题