2

I have an observable array with available items that was bound to a select dropdown box in a grid row. Users can add more rows with drop downs and select items in each of them.

The issue is once an item is selected in a dropdown row, it should not be available in any other dropdowns except the one that selected it. Removing the selected item from the array removes it from all other dropdowns but also it from the selecting dropdown.

Ex:if initially the available array contained [a, b, c, d, e, f]

dropdown 1: selected = a; available [a, c, d, f]

dropdown 2: selected = b; available [b, c, d, f]

dropdown 3: selected = e; available [c, d, e, f]

I'm trying a ko.computed approach that returns an array based on the availableItems PLUS the current selected value. But I'm having some issues getting the computed to update every dropdown.

Rough code snips:

<table>
    <tbody data-bind='foreach: item'>
        <tr>
            <td>
                <select data-bind="
                    options: $root.availableItemsWithFilter,
                    event: { onchange: changedItem }">
                </select>
            </td>
        </tr>
    </tbody>
</table>

self.availableItemsFiltered = ko.computed(function () {
    var temp = self.availableItems();
    if (currentRowNumber == self.selectedRow()) {
        temp.push(self.selectedItem);
    }
    return temp;
});

self.changedItem = function(item) {
    if (self.selectedItem != '')
    {
        self.availableItems.remove(item);
    }
}
trademark9
  • 21
  • 2

1 Answers1

2

Just out of curiosity and to remind myself how knockout works, i made another solution to this problem.

http://jsfiddle.net/rainerpl/n01fvoaq/3/

and code below

HTML

<div>


<select data-bind="optionsCaption: 'Choose...', options: $root.availableOptions.filter($element), optionsText: 'name', optionsValue: 'id', event: { change: changedItem($element)}">
</select>
<div data-bind="foreach: $root.selectedOptions().slice(1)">
    <select data-bind="optionsCaption: 'Choose...', options: $root.availableOptions.filter($element), optionsText: 'name', optionsValue: 'id', event: { change: $root.changedItem($element)}">
</select><br>

</div>
</div>

And Javascript

window.model = new function() {
    var _model = this;
    this.availableOptions = ko.observableArray([
        {name: "option1", id: 1}, 
        {name: "option2", id: 2}, 
        {name: "option3", id: 3}, 
        {name: "option4", id: 4}, 
    ]);
        this.changedItem = function( item, val ) {
            var ind;
            if ( !item ) {return;}
            if ( item.previous_id ) {
            ind =  _model.selectedOptions().indexOf(item.previous_id);

        if (ind !== (-1) ) {_model.selectedOptions.splice(ind, 1);}
            }
            ind = _model.selectedOptions().indexOf(item.value);
            if ( ind == (-1) ) {_model.selectedOptions.push(item.value);}
            item.previous_id = item.value;
        }
        this.selectedOptions = ko.observableArray([]);
        _model.availableOptions.filter = function(elem) {
            return _model.availableOptions().filter(function(item) {
                var ind = _model.selectedOptions().indexOf(item.id.toString() );
                if ( elem.value == item.id ) {return true;}
                return ind == (-1);
            });
        };
}();
ko.applyBindings(model);
Rainer Plumer
  • 3,693
  • 2
  • 24
  • 42