Reputation: 2065
I need to ensure uniqueness within my select lists.
I have a list of available options:
var viewModel =
{
availableOptions : ['Bicycle','Car','Shuttle','Motorcycle','Motorcycle'],
items : [{id:1, selectedOption: ko.observable('Car')},
{id:2, selectedOption: ko.observable()},
{id:3, selectedOption: ko.observable()}]
}
I want to foreach through my items but ensure no two items can have the same option:
<-- ko foreach: items -->
<select data-bind="options: $parent.availableOptions, value: selectedOption, optionsCaption: 'Choose...'"></select>
<!-- /ko -->
Any ideas on how to successfully achieve this where the default values stick, and only the remaining options are available to my other select's ?
Upvotes: 0
Views: 163
Reputation: 3938
You need computed here to filter items for each select
this.availableOptions = ko.computed(function () {
var item, option, i, j, isAvailable, result = [];
for (i = 0; i < root.availableOptions.length; i++) {
option = root.availableOptions[i];
isAvailable = true;
for (j = 0; j < root.items.length; j++) {
item = root.items[j];
if (item.id !== this.id && item.selectedOption() === option) {
isAvailable = false;
}
}
if (isAvailable) {
result.push(option);
}
}
return result;
}, this, { deferEvaluation: true });
See working fiddle
Edited Added deferEvaluation
to make all items to depend on all items
Upvotes: 2
Reputation: 338128
The cleanest way of course is not sending uselessly duplicated data to the browser in the first place.
The next best solution is to use an array-unique function. Most JS libraries offer such a function. For no particular reason I'm using lodash's uniq()
but you can use any library you like, for example jQuery's $.unique().
var viewModel = {
availableOptions : _.uniq(['Bicycle','Car','Shuttle','Motorcycle','Motorcycle']),
items : [{id:1, selectedOption: ko.observable('Car')},
{id:2, selectedOption: ko.observable()},
{id:3, selectedOption: ko.observable()}]
};
In general I would recommend using a class for your view model so you can do some sort of processing while you construct it. Using object literals for view models only works for the simplest cases.
For example like this.
function ViewModel(data) {
var self = this, i;
self.availableOptions: ko.observableArray(_.uniq(data.availableOptions));
self.items = ko.observableArray();
for(i = 1; i <= data.itemCount; i++) {
self.items.push({id:i, selectedOption: ko.observable()});
}
}
var viewModel = new ViewModel({
availableOptions: ['Bicycle','Car','Shuttle','Motorcycle','Motorcycle'],
itemCount: 3
});
ko.applyBindings(viewModel);
Upvotes: 0
Reputation: 1459
Try something like below -
selectedOption.subscribe(function (newValue) {
var index = availableOptions.indexOf(selectedOption());
if (index > -1) {
availableOptions.splice(index, 1);
}
});
Upvotes: 0