rwcorbett
rwcorbett

Reputation: 473

Knockout.js changing colour of <option> when using 'options' binding?

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

Answers (4)

Josie
Josie

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

Jicaar
Jicaar

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

funbrigade
funbrigade

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

Thomas Wiersema
Thomas Wiersema

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

Related Questions