7

I am doing this css binding:

css: { greenBorder: hasGreenBorder, whiteBorder: hasWhiteBorder, blackBorder: hasBlackBorder }

This works but why should my viewmodel return not just the css class name like .whiteBorder or .blackBorder.

because my logic is that from all 3 has-Variables there can only be one true the others are always false.

I think there must be a better way just to apply the class name and put this logic which classname to choose in my viewmodel, right?

4 Answers 4

7

You can use the attr binding.

data-bind="attr: { class: yourClass }"
Sign up to request clarification or add additional context in comments.

1 Comment

Is this new in knockout 2.2.0 that I can bind a class as attribute?
1

The proper way

The class binding is what you are looking for.

This binding allows you set an arbitrary css class for an element. It requires jQuery.

Usage :

<div data-bind="class: single">Single Observable Class</div>
<div data-bind="class: multiple">Multiple Observable Classes</div>



var vm = {
    single: ko.observable("red"),
    multiple: ko.observableArray(["blue","small"])
};
vm.change = function () {
    vm.single(vm.single() === "red" ? "black" : "red");

    if (vm.multiple.indexOf("small") > -1) {
        vm.multiple.remove("small");
        vm.multiple.push("big");
    } else {
        vm.multiple.remove("big");
        vm.multiple.push("small");
    }    
};

I hope it helps

3 Comments

The proper way? What is wrong about: data-bind="attr: { class: yourClass }" ?
It is error prone because attr: { class: yourClass } deletes the previous content of the class attribute. So when you write this : <div class="deletedClass" data-bind="attr: { class: yourClass }" /> The deletedClass class will disappear.
This is ok in general, but I do not have described that scenario ;-)
1

Yes, you can use an observable or computed variable as a class name, look at this sample code taken from the Knockout documentation:

<div data-bind="css: profitStatus">
   Profit Information
</div>

<script type="text/javascript">
    var viewModel = {
        currentProfit: ko.observable(150000)
    };

    // Evalutes to a positive value, so initially we apply the "profitPositive" class
    viewModel.profitStatus = ko.computed(function() {
        return this.currentProfit() < 0 ? "profitWarning" : "profitPositive";
    }, viewModel);

    // Causes the "profitPositive" class to be removed and "profitWarning" class to be added
    viewModel.currentProfit(-50);
</script>

Comments

0

You can use the attr binding to set the class (as suggested by @david.s) but when I have this type of logic I tend to put it in a custom bindingHandler.

I would make the viewModel expose some state information that would determine (in this case) border color but is not directly tied to a class:

this.state = ko.observable("complete"); //complete, pending, or cancelled (for example)

I would then use a binding handler to map this onto classes

ko.bindingHandlers.stateStyle = {
    update: function(element, valueAccessor) {
        var state = ko.utils.unwrapObservable(valueAccessor());

        if (state === "completed") {
            $(element).addClass("hasGreenBorder"); //again, just an example
        }
        else if (state === "pending") {
            //etc
        }
    }
}

Then I would use the new binding on the element

<div data-bind="stateStyle: state"></div>

This approach means that the view model is not directly referencing css classes (which feels wrong to me) and that the logic for state1 => green border is not defined in an inline binding in the view.

1 Comment

A viewmodel holds the model for the view and this is the colors etc... Why should it be wrong that a viewmodel knows a border color like black or .blackBorder? There is no advantage in having the class name in the custom binding. A viewmodel is a converter (josh smith) on steroids what you do is conversion. I do not need a binding for this.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.