简体   繁体   中英

Knockoutjs css binding not working

(Using KnockoutJs 2.0.0)

I have a list of phone numbers in my viewmodel. Each phone number has a type (home, work, mobile, etc). I want to display an icon (based on a fontawesome class) next to each phone number.

If I hardcode the icons in the css binding, everything works:

<tbody data-binding="foreach: phoneList">
    <tr>
       <td><span data-bind="css: {'icon-home' : TypeId() == 1, 'icon-building': TypeId() == 2, ... , 'icon-phone': TypeId() >= 7></span></td>
    ...
</tbody>

I wanted to replace the hardcoded list with a call to a function. I initially tried adding the function to the parent but had no success, so then I tried adding the function directly to the phone object itself both as a function and as a ko.computed() -- but neither of these work for me.

I've dummied up some code here that demonstrates the problem. If you inspect the span element of the table items, you'll see that it almost appears as if the data-biding is treating the returned string as an array of characters and setting the class based on indexes rather than treating the returned string as a class.

I'm sure this is something completely obvious, but I've been beating my head to no avail.

A computed observable should work just fine. The problem is what what you're returning from that computed observable. You need to return the definition of classes in the same format as the hard-coded version:

me.getClass = ko.computed(function() {
    return me.typeId() == 1 ? { 'mobile': true } : { 'business': true };
});

See the updated version here: http://plnkr.co/edit/qDjgMlZpXHjn5ixY3OCt

Or, you could define a custom binding to clean up the computed function a bit, though it should be noted that in this case all classes will be replaced by the output of the binding. This is probably not necessary in Knockout 3.0.0, as alluded to in the comments and other answers.

Binding:

ko.bindingHandlers.setClass = {
    update: function(element, valueAccessor, allBindings) {
        var value = ko.utils.unwrapObservable(valueAccessor());
        element.className = value;
    }
};

Observable:

me.setClass = ko.computed(function() {
    return me.typeId() == 1 ? "mobile" : "business";
});

HTML:

<td data-bind="setClass: setClass, text: typeId"></td>

A version using a custom binding is here: http://plnkr.co/edit/ryaA4mIf7oh5Biu8bKj0?p=info

Fix

Example

I updated your version of KO to 3.0.

Next, I changed your ko.computed binding for getClass from:

me.getClass = ko.computed(function() { return me.typeId == 1 ? "mobile" : "business"; });

to:

me.getClass = ko.computed(function() { return this.typeId() == 1 ? "mobile" : "business"; }, me);

Note

There may be a way to do this with KO 2.0, but I couldn't find documentation for previous versions. I imagine the issue is related to syntax if the feature exists.

An alternate way to do this is use an attr data-bind, instead of using a custom binding handler to set the class on the element.

So, you would still need to use a computed to set the observable:

me.setClass = ko.computed(function() {
    return me.typeId() === 1 ? "mobile" : "business";
});

Then use an attr binding to set the class on the html element:

<td data-bind="attr: { class: setClass }, text: typeId"></td>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM