Reputation: 91716
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
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
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
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