Anyone know if I can have an html element with both a static class name as well as a dynamic, data-bound class name using KnockoutJS? Something like this:
You can use the css
binding to add and remove a class based on the truthiness of a value, but it sounds like your viewModelProperty is the name of a class rather than a boolean.
You can use the attr
binding with the static class included like: (attr: { 'class': 'staticClassName ' + viewModelPropertyValue }
or (viewModelPropertyValue()
if it is an observable).
Otherwise, there is a community binding here that will add and remove a class in the manner that you are after: https://github.com/SteveSanderson/knockout/wiki/Bindings---class
In Knockout 2.2.0, you can!
<span class='staticClassName' data-bind='css: viewModelPropertyValue'></span>
I've seen a lot of different answers for this problem, mostly in combine dynamic and static classes through css binding, knockout.js which doesn't describe your problem, but offers solutions that could be applied here. Implementing ie. OOCSS principles is not easily done using Knockout, I've found.
The only solution that appealed to me was to use a string concatenation
<span data-bind="css: [ 'item', 'item-' + name ].join(' ')"></span>
You can use this in your example. In my opinion this is the least obtrusive, but it's ugly code and quickly becomes beyond readable.
However, if you are able to use ECMAScript2015 in your project, you have the ability to use computed property names, which look like this.
var name = "apple";
var items = { [ "item-" + name ] : "juicy" }
This means you can leave out the [].join(' ')
functionality and add your classes the way Knockout actually prescribes it:
<span data-bind="css : { 'item' : true, [ 'item-' + name ] : true }>
It's more elegant, easily extendable and readable. Only down point of course is that it is ECMAScript 2015. If you can, use computed property names, if not I would revert back to the [].join(' ')
-statement.
To see this in action and play around with it a little, I've added a working example.
Read more about computed property names at https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/Object_initializer#Computed_property_names
var viewModel = {};
viewModel.items = ko.observableArray([
{ 'name' : 'Apple' },
{ 'name' : 'Mango' },
{ 'name' : 'Raspberry' }
])
ko.applyBindings(viewModel);
.item {
font-family: sans-serif
}
.item-Mango span {
background-color: orange;
color: #FFF;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<ul data-bind="foreach: items">
<li data-bind="css : { 'item' : true, [ 'item-' + name ] : true}">
<span data-bind="text: name"></span>
</li>
</ul>