What is the best way to hide the screen while knockout js bindings are being built?
Asked Answered
P

4

76

I'm a huge knockoutjs fan. I use it for all my web development now and simply love it. One thing that I've not been able to figure out though is how to hide the UI while the knockoutjs bindings are being built.

For example, I have a very robust user interface with lots of templates being used on my page. The problem that I'm noticing is that when the user first visits the page, they see all of my templates for a split second before the bindings kick in and hide them.

What is the best way to fix this problem? I've tried using helper classes to hide them, but then the templates are not able to be displayed using 'visible' and 'if' bindings unless I remove the helper class reference (ie. ui-helper-hidden).

Prospectus answered 2/3, 2012 at 11:34 Comment(0)
B
71

There are a couple of strategies that you can use here.

-One is to place all of your actual content into templates that live in script tags (does work fine with native templates). Within the template, you can then use control-flow bindings. This would be like:

<div data-bind="template: 'contentTmpl'"></div>

<script id="contentTmpl" type="text/html">
   <ul data-bind="foreach: items">
       <li data-bind="text: name"></li>
   </ul>
</script>

-Another choice is to use style="display: none" on the container element along with a visible binding that can be tied to a loaded observable where you change the observable to true after the bindings have been applied.

Barm answered 2/3, 2012 at 14:28 Comment(3)
For the record, I was using the 'loaded' suggestion, and it wasn't working for me. All of my js references are at the bottom of my page, and the markup was visible until the applyBindings call (very last line of js). I just wanted to add this as a note because that was the problem I was trying to solve initially. Thanks again!Prospectus
I edited the answer to describe what the way that the loaded observable could work. You need to add style="display: none" on a container element along with visible: loaded, then toggle it to true after your bindings have been applied. The visible binding will remove the display: none (it can't control what is in your css).Barm
@RPNiemeyer, the second approach might not do so well for SEO if the server was returning non JS pages. In my case knockout adds a layer to the UI generated by the server, display:none might not get picked up by bots.Roley
F
197

I was just googleing for this, and after using the observable way, I thought of another approach:

<div style="display: none" data-bind="visible: true">
  <ul data-bind="foreach: items">
    <li data-bind="text: name"></li>
  </ul>
</div>

You don't need an observable, the visible will always evaluate to true once the data binding is done.

Fargone answered 20/12, 2012 at 17:34 Comment(6)
Excellent! One more optimization on top of that when you don't want that extra div: <ul data-bind="foreach: items, visible: true"> <li data-bind="text: name"></li> </ul>Pilloff
Thx for that! I should add that I just added the style/data-bind to my existing div and for some reason that only hid part of it. So I added an outer div. Btw I also added this before <div data-bind='visible: false'> Screen loading... </div>Erbil
Excellent! You could also have a div that contains a loading animation, with a data-bing of "visible: false".Idou
Angular tries to do way too much. I will always prefer the simplicity of knockout in combination with other libraries like SammyJSVirgilio
A little late to the party perhaps, but you could do <div class="beforeReady" data-bind="css: {ready: true}"> if you wanted to do css animations to display it (like opacity or something)Plumule
Simple and clear solution! Need to add both to the upmost divMcmillin
B
71

There are a couple of strategies that you can use here.

-One is to place all of your actual content into templates that live in script tags (does work fine with native templates). Within the template, you can then use control-flow bindings. This would be like:

<div data-bind="template: 'contentTmpl'"></div>

<script id="contentTmpl" type="text/html">
   <ul data-bind="foreach: items">
       <li data-bind="text: name"></li>
   </ul>
</script>

-Another choice is to use style="display: none" on the container element along with a visible binding that can be tied to a loaded observable where you change the observable to true after the bindings have been applied.

Barm answered 2/3, 2012 at 14:28 Comment(3)
For the record, I was using the 'loaded' suggestion, and it wasn't working for me. All of my js references are at the bottom of my page, and the markup was visible until the applyBindings call (very last line of js). I just wanted to add this as a note because that was the problem I was trying to solve initially. Thanks again!Prospectus
I edited the answer to describe what the way that the loaded observable could work. You need to add style="display: none" on a container element along with visible: loaded, then toggle it to true after your bindings have been applied. The visible binding will remove the display: none (it can't control what is in your css).Barm
@RPNiemeyer, the second approach might not do so well for SEO if the server was returning non JS pages. In my case knockout adds a layer to the UI generated by the server, display:none might not get picked up by bots.Roley
C
0

Here's a CSS-only method if you're worried about unstyled widgets showing up before the bind for MVVM implementations.

[data-role]:not([role], [tabindex]) {
    visibility: hidden;
}

I haven't tested it on all Kendo widgets, but it seems to work for most.

Claudiaclaudian answered 25/4, 2016 at 15:28 Comment(0)
R
0

Here is alternative approach using classes for "hide and "show" instead of an inline style. Add a "hide" class to the element that needs to be hidden until the contents load, and add a "css" data-binding to make it be shown when it is bound.

<div class="hide" data-bind="css: {'show': true}">

</div>

The 'hide' and 'show' classes are already defined in Bootstrap.

If Bootstrap is not being used, the CSS can be defined as:

.hide {
  display: none !important;
}
.show {
  display: block !important;
} 

The order matters. The "hide" class should be defined before "show".

Rebus answered 18/3, 2019 at 13:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.