Reputation: 588
I have an array of texts that I display in a <select>
.
The texts may have different version no, and I want to filter the <select>
based upon the latest version only.
I guess there are more elegant ways to do it (suggestions welcome), but I´ve chosen to use 2 <select>
s set to alternate visibility depending on the checkbox.
The code is a hack, but the result looks pretty good. Unfortunately there´s a bug.
I have two observables indicating the selected option in their respective arrays:
self.SelectedText = ko.observable();
self.SelectedUnique = ko.observable();
Both have subscriptions, but I cannot link them together in both subscription, so I have chosen one to be indipendant on the other like this:
self.SelectedUnique.subscribe(function (text) {
if (text) {
self.SelectedText(text);
}
});
However, the get out of sync.
Scenario 1: select text 1,2,3. [OK] Scenario 2: select text 2; check "Latest versions only"
This causes no options ("Choose…") to be displayed. Not what I want.
It gets worse.
Scenario 3: uncheck; select text 3; Then check "Latest versions only" again.
Now the select option chosen is set to select option no 2 of the unfiltered.
There´s probably a simple issue. I just can´t make it work probably. Here´s the fiddle: Fiddle: http://jsfiddle.net/h5mt51gv/6/
All help and suggestions appreciated!
Upvotes: 0
Views: 76
Reputation: 338326
I have streamlined your approach:
<select>
binds to a computed list of options (visibleTextBatches
)latestOnly
), effectively toggling between the full and the filtered listlatestTextBatches
) is another computed that holds the latest version for each group <select>
stores the actual selected TextBatch
object in an observable (selectedTextBatch
)visibleTextBatches
that causes the latest selectable TextBatch
to become the current one when the list is filtered. When the list is unfiltered, it does nothing.function TextBatch(data) {
this.textbatchId = data.textbatchId;
this.parentId = data.parentId;
this.version = data.version;
this.title = ko.observable(data.title);
}
function ViewModel() {
var self = this;
// read up on the mapping plugin, too
self.textBatches = ko.observableArray([
new TextBatch({textbatchId: 1, parentId: 1, version: 1, title: "TB1.1"}),
new TextBatch({textbatchId: 2, parentId: 1, version: 2, title: "TB1.2"}),
new TextBatch({textbatchId: 3, parentId: 3, version: 1, title: "TB2.1"})
]);
self.selectedTextBatch = ko.observable();
self.latestOnly = ko.observable(false);
self.latestTextBatchGroups = ko.computed(function () {
var latest = {};
ko.utils.arrayForEach(self.textBatches(), function (batch) {
if (!latest.hasOwnProperty(batch.parentId) ||
batch.version > latest[batch.parentId].version
) latest[batch.parentId] = batch;
});
return latest;
});
self.latestTextBatches = ko.computed(function () {
return ko.utils.arrayFilter(self.textBatches(), function (batch) {
return batch === self.latestTextBatchGroups()[batch.parentId];
});
});
self.visibleTextBatches = ko.computed(function () {
return self.latestOnly() ? self.latestTextBatches() : self.textBatches();
});
self.visibleTextBatches.subscribe(function () {
var selectedBatch = self.selectedTextBatch();
if (selectedBatch && self.latestOnly()) {
self.selectedTextBatch(
self.latestTextBatchGroups()[selectedBatch.parentId]
);
}
});
}
ko.applyBindings(new ViewModel());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<div>
<select data-bind="
options: visibleTextBatches,
optionsText: 'title',
optionsCaption: 'Select...',
value: selectedTextBatch
" />
</div>
<div>
<input type="checkbox" id="chkLatestOnly" data-bind="checked: latestOnly" />
<label for="chkLatestOnly">Latest only</label>
</div>
<hr />
<pre data-bind="text: ko.toJSON($root, null,2)"></pre>
Upvotes: 1