【问题标题】:Knockout options binding: how to remove items dynamically from popup if they are selected淘汰赛选项绑定:如果项目被选中,如何从弹出窗口中动态删除项目
【发布时间】:2014-07-31 21:37:58
【问题描述】:

这是问题的一个示例,在这种情况下,有人选择披萨的配料(我的现实世界问题与此类似): http://jsfiddle.net/csabatoth/aUH2C/4/

HTML:

<h2>Pizza toppings (<span data-bind="text: toppings().length"></span>)</h2>
<table class="table table-bordered">
    <thead><tr>
        <th>Topping</th><th>Number of units</th>
    </tr></thead>
    <tbody data-bind="foreach: toppings">
        <tr>
            <td><select data-bind="options: $root.availableToppings(), value: name, optionsText: 'name'"></select></td>
            <td><input data-bind="value: num" /></td>
            <td><a href="#" data-bind="click: $root.removeTopping">Remove</a></td>
        </tr>
    </tbody>
</table>

<button type="button" class="btn btn-primary" data-bind="click: addTopping, enable: toppings().length < 5">Add another topping</button>

JS:

// Class to represent a possible topping
function Topping(name) {
    var self = this;
    self.name = name;
    // This will have other properties
}

// Class to represent a row in the grid
function ToppingRow(topping, num) {
    var self = this;
    self.topping = ko.observable(topping);
    self.num = ko.observable(num);

    self.toppingName = ko.computed(function() {
        return self.topping().name;
    });
}

function ToppingsViewModel() {
    var self = this;

    // Non-editable catalog data - would come from the server
    self.availableToppings = ko.observableArray([
        new Topping("Mushroom"),
        new Topping("Pepperoni"),
        new Topping("Cheese"),
        new Topping("Olives"),
        new Topping("Chicken")
    ]);    

    // Editable data
    self.toppings = ko.observableArray([
        new ToppingRow(self.availableToppings()[0], 1)
    ]);

    // Operations
    self.addTopping = function() {
        self.toppings.push(new ToppingRow(self.availableToppings()[0], 1));
    }
    self.removeTopping = function(topp) { self.toppings.remove(topp) }    
}

ko.applyBindings(new ToppingsViewModel());

我想要的是:当用户选择一个浇头时,该选项应该从弹出列表中消失。一旦用户删除了顶部,它应该重新出现在弹出窗口中。换句话说:我不希望用户多次添加相同的浇头。该怎么做?

(或者现在我想如果我应该以一种完全不同的方式来处理这个问题,并且会在左侧有一个带有浇头的列表,并且用户可以从那里拖放到正确的目的地列表......)。在现实世界的例子中,我认为“浇头”的数量可能有几十个。

【问题讨论】:

    标签: javascript html knockout.js binding


    【解决方案1】:

    您可以通过使用带有 1 个下拉菜单的顶部选择器来稍微简化此操作。然后,当您单击添加时,它将当前选定的项目插入到选定的浇头部分,然后从可用列表中删除该选项。

    如果您觉得自己很聪明,您还可以将下拉列表绑定到不包括已选择项目的计算项目集合。 (underscore.js 也会对此有很大帮助)。

    (Fiddle)

    JS

    // Class to represent a possible topping
    function Topping(name) {
        var self = this;
        self.name = name;
        // This will have other properties
    }
    
    // Class to represent a row in the grid
    function ToppingRow(topping, num) {
        var self = this;
        self.topping = topping;
        self.num = ko.observable(num);
    
        self.toppingName = ko.computed(function() {
            return self.topping.name;
        });
    }
    
    function ToppingsViewModel() {
        var self = this;
    
        // Non-editable catalog data - would come from the server
        self.allToppings = ko.observableArray([
            new Topping("Mushroom"),
            new Topping("Pepperoni"),
            new Topping("Cheese"),
            new Topping("Olives"),
            new Topping("Chicken")
        ]);   
    
        self.selectedToppings = ko.observableArray([]);
    
        self.availableToppings = ko.computed(function(){
            return _.reject(self.allToppings(), function(topping) {
                return _.contains(_.pluck(self.selectedToppings(), 'topping'), topping);
            })
        });
    
        self.currentlySelectedTopping = ko.observable();
        self.currentlySelectedToppingNumber = ko.observable(1);
    
        // Operations
        self.addTopping = function() {
            self.selectedToppings.push(new ToppingRow(self.currentlySelectedTopping(), self.currentlySelectedToppingNumber()));
        }
        //self.removeTopping = function(topp) { self.toppings.remove(topp) }    
    }
    
    ko.applyBindings(new ToppingsViewModel());
    

    HTML

    <h2>Pizza toppings</h2>
    
    <table class="table table-bordered">
        <thead><tr>
            <th>Topping</th><th>Number of units</th>
        </tr></thead>
        <tbody>
            <tr>
                <td><select data-bind="options: availableToppings, value: currentlySelectedTopping, optionsText: 'name'"></select></td>
                <td><input data-bind="value: currentlySelectedToppingNumber" /></td>
                <td><a href="#" data-bind="click: function(){alert('hello');}">Remove</a></td>
            </tr>
            <!-- ko foreach: selectedToppings -->
            <tr><td data-bind="text: toppingName"></td><td data-bind="text: num"></td></tr>
            <!-- /ko -->
        </tbody>
    </table>
    
    <button type="button" class="btn btn-primary" data-bind="click: addTopping, enable: availableToppings().length">Add another topping</button>
    

    【讨论】:

    • 感谢您的建议!所以在第一种情况下会有一个明确的添加按钮,我可以对它的点击做出反应。在第二种情况下,我需要研究下划线的帮助。
    • 我添加了一个小提琴,很抱歉,但我注释掉了删除功能,但我相信你应该会发现让它工作起来相对简单。
    【解决方案2】:

    我不明白你为什么要让简单的事情变得困难。这是一些修改后的版本。

    function Topping(name) {
        var self = this;
        self.name = name;
        self.active = ko.observable(false)
    
        self.toggle = function () {
            self.active(!self.active())
        }
        // This will have other properties
    }
    
    // Class to represent a row in the grid
    function ToppingRow(name, num) {
        var self = this;
        self.name = name;
        self.num = num;
    }
    
    function ToppingsViewModel() {
        var self = this;
    
        // Non-editable catalog data - would come from the server
        self.availableToppings = ko.observableArray([
            new Topping("Mushroom"),
            new Topping("Pepperoni"),
            new Topping("Cheese"),
            new Topping("Olives"),
            new Topping("Chicken")
        ]); 
    
        self.list = ko.observableArray()
        self.num = ko.observable(1) 
        self.selected = ko.observable()  
    
    
        // Operations
        self.addTopping = function() {
            self.list.push(new ToppingRow(self.selected(),self.num()));
            self.setAvailableToppings(self.selected())
        }
        self.removeTopping = function(item) { 
            self.list.remove(item) 
            self.setAvailableToppings(item.name)
        } 
    
        self.setAvailableToppings   = function (name) {
            var items = []
            ko.utils.arrayForEach(self.availableToppings(),function (item) {
                if(item.name == name){
                    item.toggle()
                }
                items.push(item)
            })
            self.availableToppings([])
            self.availableToppings(items)       
            var selected = ko.utils.arrayFirst(self.availableToppings(),function (item) {
                return item.active() == false
            })
            if(selected){
                self.selected(selected.name)
            }
        }
    
        self.setOptionDisable = function(option, item) {
            ko.applyBindingsToNode(option, {disable: item.active()}, item);
        }
    }
    
    
    $(document).ready(function(){
        ko.applyBindings(new ToppingsViewModel());      
    })
    

    然后查看

    <h2>Pizza toppings (<span data-bind="text: list().length"></span>)</h2>
    
    <table class="table table-bordered">
        <thead><tr>
            <th>Topping</th><th>Number of units</th>
        </tr></thead>
        <tbody data-bind="foreach: list">
            <tr>
                <td data-bind="text:name"></td>
                <td data-bind="text: num"></td>
                <td><a href="#" data-bind="click: $root.removeTopping">Remove</a></td>
            </tr>
        </tbody>
    </table>
    <br clear="all"/>
    <select data-bind="
        options: $root.availableToppings(), 
        value: $root.selected, 
        optionsText: 'name',
        optionsValue : 'name',
        optionsAfterRender: $root.setOptionDisable,
        enable: list().length < 5
    ">
    </select>
        <input data-bind="value: $root.num,enable: list().length < 5" />
        <br clear="all"/>
    <button type="button" class="btn btn-primary" 
        data-bind="
            click: addTopping, 
            enable: list().length < 5
    ">Add another topping</button>
    

    Fiddle Demo

    【讨论】:

    • 那个也很棒!现在我不知道我应该标记哪个正确。
    猜你喜欢
    • 1970-01-01
    • 2017-09-22
    • 1970-01-01
    • 1970-01-01
    • 2013-12-06
    • 2013-04-24
    • 2019-05-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多