GraemeMiller
GraemeMiller

Reputation: 12253

How to create linked dropdowns sharing a single list and ensure each value can only be selected in one dropdown?

I am trying to create a group of dropdowns using knockout out that allow users to select up to 3 values from a list e.g. colours. The list starts as:- Red,orange,yellow,green,blue,indigo,violet

DropDown 1 - Select any of the 7
DropDown 2 - Select any of the 6 remaining
Dropdown 3 - Select any of the 5 remaining

If the user goes back and changes DropDown 1 to something they should only have the choices of the other remaining colours (and the one in Drop Down 1). If they then change it, I would be able to go to dropdown 2 or 3 and change that to the value that used to be in 1.

I think I need an initial array containing the 7 items, then I need an observable per dropdown. The 3 obseravables would have to be based on the initial data and excluding the selected of the other three dropdowns. I am really struggling with this. I can't even come close to implementing it.

Is this even possible or an appropriate use for Knockout or should I just look at JS with an onChange

Upvotes: 2

Views: 223

Answers (1)

Michael Best
Michael Best

Reputation: 16688

This is definitely possible in Knockout. And there's probably 10 ways to do it. I've come up with one way here:

http://jsfiddle.net/mbest/wfW97/

Here's the code for reference:

function ViewModel() {
    var self = this;
    self.colors = ['red','orange','yellow','green','blue','indigo','violet'];
    self.selections = [];
    ko.utils.arrayForEach(self.colors, function() {
        self.selections.push(ko.observable());
    });
    self.selfAndUnselectedColors = function(index) {
        var selfColor = self.selections[index]();
        return ko.utils.arrayFilter(self.colors, function(color) {
            return color === selfColor || !ko.utils.arrayFirst(self.selections, function(sel) {
                return color === sel();
            });
        });
    }
}
ko.applyBindings(new ViewModel());

And HTML:

<div data-bind="repeat: colors.length">
    <select data-bind="options: selfAndUnselectedColors($index), optionsCaption: 'select a color', value: selections[$index]"></select>
</div>​

I'm using my repeat binding plugin to create the repeated select elements, but you could use some other method if you wanted.

Upvotes: 2

Related Questions