In Knockout, the "options
" binding has an optional argument `optionsAfterRender which is used to modify the individual option tags as they are inserted. You can find more details in the documentation.
For one of my select lists, I am having to use a foreach
binding instead, because it requires a two-level binding using optgroup
.
<select data-bind="foreach: { data: availableData,
value: editDataId">
<optgroup data-bind="attr: {label: groupTitle}, foreach: groups">
<option data-bind="value: id, attr: {title: name }"></option>
</optgroup>
</select>
However, I would also like to modify these options after binding.
There is an afterRender
option for foreach
, but it seems to behave very differently than optionsAfterRender
. I was able to get it to execute against all the options in the select list as follows:
<select data-bind="foreach: { data: availableData,
value: editDataId,
afterRender: doStuff">
<optgroup data-bind="attr: {label: groupTitle}, foreach: groups">
<option data-bind="value: id, attr: {title: name }"></option>
</optgroup>
</select>
And then in the viewmodel
doStuff(elements, data): void {
for (let entry of elements[1].querySelectorAll("option")) {
ko.applyBindingsToNode(entry, {disable: true }, entry);
}
}
(I don't really want to disable them all - it's just a simple test) - but this lead to the curious result of the entire select list not rendering at all. On inspection the nodes are still there - in the HTML and they can be traveresed and logged - but they're not appearing on the page.
This isn't because they're disabled. Something in the binding is causing the whole thing to go screwy. Is there a way I can mimic the operation of optionsAfterRender
on this foreach
binding?
Aside from fixing the un-closed foreach binding typo I also found I needed to change the option's "title" binding to "label" to get the individual option text to show up. Other than that your code seems to function as expected.
function viewModel(){
var self = this;
self.editDataId = 1;
self.availableData = [
{ groupTitle: 'group1', groups: [ {id: 1, name: 'item1'}, {id: 2, name: 'item2'} ] } ,
{ groupTitle: 'group2', groups: [ {id: 3, name: 'item3'}, {id: 4, name: 'item4'} ] }
];
self.doStuff = function(elements, data) {
for (let entry of elements[1].querySelectorAll("option")) {
ko.applyBindingsToNode(entry, { disable: true }, entry);
}
}
}
ko.applyBindings(new viewModel());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<select data-bind="foreach: { data: availableData,
value: editDataId,
afterRender: doStuff }">
<optgroup data-bind="attr: {label: groupTitle}, foreach: groups">
<option data-bind="value: id, attr: {label: name}"></option>
</optgroup>
</select>