Knockout observable Array not reflecting in UI (foreach binding)
I am adding data to a tag list from a grid (by validating rows of data). When this happens, I want the tag list to be sorted (for example, sorted alphabetically by name).
The sort result should obviously reflect in the UI, but from what I've tried that doesn't work in my case.
Here is a sample fiddle: http://jsfiddle.net/hLpLobo2/5/
To make sure it's sorted, I call the function sortPersonsAlphabetically
in the callback foreach
afterAdd
:
<div class="tag-list" data-bind="foreach: {
data: tags, as: 'tag',
afterAdd: sortPersonsAlphabetically
}">
<div class="tag-item">
<span class="tag-item-value tag-item-value-name" data-bind="text: tag.name"></span>
<span class="tag-item-separator">:</span>
<span class="tag-item-value tag-item-value-age" data-bind="text: tag.age"></span>
</div>
</div>
but this weirdly only works after adding another item ("second choice").
In the example script I provided, I added a tag <pre>
where it is clear that the array is correctly sorted, but it is not reflected in the tag list UI.
I also tried wrapping the sort function in setTimeout
with a 1ms delay and seems to fix it, but with some visible flicker, which is not acceptable in my opinion and is more of a hack.
Is there a clean way to do this?
source to share
Afteradd is really meant to update the DOM in response to data changes, not to make further changes to the data. The result you are getting is weird, but I agree.
I recommend that you use computed sorted tags to generate,
self.sortedTags = ko.computed(function () {
var data = self.tags();
return data.sort(function(left, right) {
return left.name == right.name ? 0 : (left.name < right.name ? -1 : 1);
});
});
and display this in your foreach:
<div class="tag-list" data-bind="foreach: {
data: sortedTags, as: 'tag'
}">
source to share