Reputation: 473
Is it possible to alter the styling (using 'style' or 'css' binding) of a select list's option element when using the 'options' binding on a select list? Or can this only be done by using a 'foreach' on the select list and altering the styling for each ?
I have this in code:
<select id="components-select" size="4" name="components-select"
data-bind=" options: combinedComponents,
optionsText: 'displayName',
optionsValue: 'id',
value: chosenComponent"></select>
but if I append style: {color: isDefault() === true ? 'black' : 'red'}
then the entire list is coloured Red if isDefault
returns false.
Is the only way to achieve this to code it this way:
<select id="components-select" size="4" name="components-select"
data-bind="foreach: combinedComponents">
<option data-bind="value: id, text: displayName, style: {color: isDefault() === true ? 'black' : 'red'}"></option>
</select>
Or is there some form of Knockout.js wizardry that I am not aware of?
Thanks!
Upvotes: 8
Views: 3709
Reputation: 21
Try the 'optionsAfterRender' Binding which in this case works fine. http://jsfiddle.net/cZRJN/243/
var viewModel = function() {
this.combinedComponents = ko.observableArray([{
displayName: 'item1',
id: 1,
isDefault:true
}, {
displayName: 'item2',
id: 2,
isDefault:false
}, {
displayName: 'item3',
id: 3,
isDefault:true
}]);
OptionsAfterRender = (option, item) => {
ko.applyBindingsToNode(option, {style: { color: item.isDefault ? 'red' : 'black'}}, item);
};
this.chosenComponent= ko.observable(1);
}
ko.applyBindings(new viewModel());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.1/knockout-min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet"/>
<select id="components-select" size="4" name="components-select"
data-bind=" options: combinedComponents,
optionsText: 'displayName',
optionsValue: 'id',
value: chosenComponent,
optionsAfterRender:OptionsAfterRender
"></select>
Upvotes: 1
Reputation: 1114
To add up the what has already been said, there is one feature of Knockout that I find get's overlooked a lot and is very handy in these situations: $index
. For example, I am making a list where I want the first option in the list to be black and the rest to be red. So I can just modify what you have as your second option like so:
<select id="components-select" size="4" name="components-select"
data-bind="foreach: combinedComponents">
<option data-bind="value: id, text: displayName,
style: {color: $index === 0 ? 'black' : 'red'}"></option>
</select>
Or if you want to alternate colors just use a modulus check.
<select id="components-select" size="4" name="components-select"
data-bind="foreach: combinedComponents">
<option data-bind="value: id, text: displayName,
style: {color: $index % 2 === 1 ? 'black' : 'red'}"></option>
</select>
Upvotes: 0
Reputation: 321
To expand on Thomas Wiersema's answer, the way you'd want to approach handling that on a per-row basis is something like:
<select id="components-select" size="4" name="components-select"
data-bind="foreach: combinedComponents">
<option data-bind="value: id, text: displayName, style: {color: getColorFor.call(null, $data) }"></option>
</select>
then, in JavaScript, attach a function to your parent object like so (I'm making some assumptions, of course, like your parent object being called vm
and isDefault
belonging to a combinedComponent):
vm.getColorFor = function(component) {
return component.isDefault() === true ? 'black' : 'red';
}
If you're not sure what call
does, check out bind vs apply vs call
I hope that helps -- let me know if I can elaborate!
Upvotes: 2
Reputation: 209
To answer your question, yes that is the best way I believe.
with the code style: {color: isDefault() === true ? 'black' : 'red'}
you bind(add) a style to the associated DOM element. In this case the whole <select>
tag. Not a <option>
tag like you want. That's why your entire list changes color.
Take a look at the knockoutjs docs for more info about style binding.
Upvotes: 1