敲除选项绑定:如果选中它们,如何从弹出窗口中动态删除项目

时间:2014-06-10 23:46:52

标签: javascript html knockout.js binding

以下是问题的示例,在这种情况下,有人选择披萨的配料(我的现实世界问题与此类似): 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());

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

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

2 个答案:

答案 0 :(得分:2)

你可以通过一个顶部选择器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>

答案 1 :(得分: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