Mike Christensen
Mike Christensen

Reputation: 91716

How to hide a button in Knockout.js based on bound value

I have the following button in my HTML template that I only want to show if CanCancel is true:

<button data-bind="click: CancelProject, visible: CanCancel">Cancel Project</button>

The problem is the model takes 1-2 seconds to bind, so I actually see the button for a few seconds, then it disappears when the data is fully bound. I want the button to be hidden, and then appear if CanCancel is true.

I've tried to use CSS to set the initial state of the button:

<button class="hidden" data-bind="click: CancelProject, visible: CanCancel">Cancel Project</button>

And in my CSS:

DIV.buttons button.hidden { display: none; }

However, when I do that, I never see the button. This is because Knockout.js will not override the inline style of the button with display: inherit; if the value is true.

Is there a way to get Knockout to explicitly set the inline display style no matter what?

Upvotes: 0

Views: 7210

Answers (3)

Mike Christensen
Mike Christensen

Reputation: 91716

Ok I've found a few easy ways to fix this. Probably the easiest is by using the style binding:

<button class="hidden" data-bind="click: CancelProject, style: { display: CanCancel ? 'inherit' : 'none' } ">Cancel Project</button>

The hidden CSS selector will set the initial state to hidden, and the bound inline style will override this when the model is bound.

The second way might be a little bit more flexible. I added a CSS class to the <body> tag:

<body class="loading">

Now, I can hide certain elements while the page is loading:

BODY.loading DIV.buttons { display: none; }

Lastly, when I bind the data, I can remove the class:

ko.applyBindings(model);
$(document.body).removeClass('loading');

This would allow me to control exactly how various elements behave when the page is being loaded using pure CSS.

Upvotes: 2

user677526
user677526

Reputation:

The quick and dirty solution to this is as follows:

<button class="hidden" data-bind="click: CancelProject, style: { display: CanCancel ? 'inherit' : ''}">Cancel Project</button>

See more about the style binding here.

All that said, it's quick and dirty, and you might want to go with Matt's answer if you're working with a larger project/framework.

Upvotes: 1

Matt Burland
Matt Burland

Reputation: 45155

I usually wrap everything that's going to be bound by knockout in a div set with display:none and then either make it visible with (for example) jQuery right after the ko.applyBindings, or else use a custom knockout binding to make it visible linked to a loaded, ready or similar property (useful if your VM involves loading data via AJAX) or even just a with binding in my view model.

Here's a simple custom binding that uses jQuery's .show() to make an element visible, even if it was initially set to display:none:

ko.bindingHandlers["realVisible"] = {
    init: function(element, valueAccessor) {
        var val = ko.utils.unwrapObservable(valueAccessor());
        if (val) {
            $(element).show();
        }
        else {
            $(element).hide();
        }
    },
    update: function(element, valueAccessor) {
        var val = ko.utils.unwrapObservable(valueAccessor());
        if (val) {
            $(element).show();
        }
        else {
            $(element).hide();
        }
    }
}

Here's a demo fiddle

Upvotes: 1

Related Questions