timing of page rendering

193 views
Skip to first unread message

Noirabys

unread,
Apr 17, 2018, 9:39:30 AM4/17/18
to KnockoutJS
hi,
anyone knows when exactly the rendering of the page happens in knockoutjs ? 
and is it possible to know when rendering has been completed ?


var myArray = ko.observableArray();

function add(){
    myArray.push('A');
    // at this point the span doesn't yet exists
}

<div data-bind="foreach: myArray">
     <span data-bind="text: $data"></span>
</div>

best regards,
 noirabys

Andrew Vickers

unread,
Apr 18, 2018, 12:03:44 PM4/18/18
to KnockoutJS
If you mean the initial rendering of the elements from a foreach or template, there is a hook for afterRender.  If you need to know when a new element has been rendered, there is a hook for afterAdd.  Look down towards the bottom of the notes on each bindings documentation.

Noirabys

unread,
Apr 19, 2018, 2:11:20 AM4/19/18
to KnockoutJS
thanks for the reply,

yes i'm aware of the template afterRender
but the question is not specific to the array
let's have a simple observable;

var a = ko.observable();

function b(){
   a('xxx');
   // update of gui not done at this point
}
i would like to use the final dimensions of elements in the gui for further processing

any idear ?

Andrew Vickers

unread,
Apr 20, 2018, 5:46:52 PM4/20/18
to KnockoutJS
Oh, I see.  Hmm...

Anytime I have needed that precise level of control over rendering, I have used the d3.js library, either directly or via a custom binding.

Maybe someone else is more familiar with knockouts internal pubsub flow and can advise you on how to setup a subscribable to capture what you need.

Shallom Gabriels

unread,
May 15, 2018, 3:32:15 PM5/15/18
to KnockoutJS
@ noirabys
Did you find a solution yet? I am facing the same issue too. 

Noirabys

unread,
May 16, 2018, 11:06:27 AM5/16/18
to KnockoutJS
hi Shallom,
 sorry, no the question is still open, but i don't think it is an issue.

Noirabys

unread,
May 16, 2018, 11:08:08 AM5/16/18
to KnockoutJS
would be cool, if one of the knockout developers could help ?

Michael Best

unread,
May 17, 2018, 4:18:11 AM5/17/18
to KnockoutJS
Perhaps I can help. Why do you want to know when rendering is complete?

Shallom Gabriels

unread,
May 17, 2018, 11:02:33 AM5/17/18
to KnockoutJS
I am loading my viewModel and template using RequireJs. After ko.applyBindings executes, each value in the array gets computed and rendered to the screen one by one. This causes a significant delay especially for large data sets on a Single Page Application. I am still looking for a way to make the computation faster(suggestions are welcomed). But for now, I am looking for a way to hide everything on the page until all components are registered

Michael Best

unread,
May 17, 2018, 11:33:58 PM5/17/18
to KnockoutJS
In Knockout 3.5, we're adding a descendantsComplete binding event that I think will help you. You can download the 3.5.0 release candidate and try it in your application.

Noirabys

unread,
May 18, 2018, 7:30:53 AM5/18/18
to KnockoutJS
hi michael,
  i'm trying to do print processing, which means i would like to add content to a "page" container. the workflow is: adding next content , see if it fits, if so add further, if not switch to next page.

Shallom Gabriels

unread,
May 18, 2018, 10:26:12 AM5/18/18
to KnockoutJS
I have tried using the descendantsComplete binding event without any success. Please can you provide a JSFiddle example on how you would use the descendantsComplete binding event? Your help is very much appreciated.

SLG

unread,
May 21, 2018, 5:32:11 PM5/21/18
to KnockoutJS
Have you tried Brian Hunt fast for each?

I feels like it is not the computed causing the issue, but the for each loop through large amount of data.

Shallom Gabriels

unread,
May 22, 2018, 12:41:37 PM5/22/18
to KnockoutJS
Hello SLG, the application uses the JavaScript Array forEach() Method. It does not use Knockoutjs' "foreach" binding... so I can't use Brian Hunt's fast for each. Thanks! Let me know if you have anymore suggestions.

Andrew Vickers

unread,
May 22, 2018, 1:28:44 PM5/22/18
to KnockoutJS
Hello Shallom,

It sounds to me like, whether or not you are able to use the descendantsComplete binding to stop the flickering, that might amount to merely treating the symptom.

Knockout was intended for use with the MVVM pattern.  I think there is sometimes a tendency to implement a VVM pattern, with the View Model doubling as the Model.  That is fine for simple applications and websites, but does not scale well to complex SPAs/PWAs.

The view model is really just supposed to prep model data for the view.  It should not generally be performing complex logic/mutations on large arrays.  There are two ways to deal with this depending upon what's going on:

Most likely, the array mutation should be taking place in the model.  This could be performed on the server, handled by the database (map/reduce or query), or done in a web worker to get it out of the rendering thread, which should alleviate the DOM blocking issues (flicker).

If it really is such a massive array that simply prepping it for the view is blocking the DOM, then you can implement a pagination strategy.

    this.paginated = ko.computed(function() {
        let first = self.currentPage() * self.pageSize;
        let temp = self.fullArray.slice(first, first + self.pageSize);
// perform view logic here on the small array
return temp;
 });

This way you are only performing the logic on the portion of the array that will currently be rendered on the screen rather than pre-processing a potentially massive array.

If you need to render a massive amount of data points on the screen at once, using the canvas and a lower level library like d3.js might be more appropriate.

SLG

unread,
May 22, 2018, 4:35:03 PM5/22/18
to KnockoutJS
Because you mentioned flickering, it typically happened when the view model is redraw every time a new element is inserted into an observable array.

Can you wait until all computation is complete, then assign to the array at once?

Some code will help us pinpointing the issue for you.


On Thursday, May 17, 2018 at 10:02:33 AM UTC-5, Shallom Gabriels wrote:

Shallom Gabriels

unread,
May 23, 2018, 11:08:38 AM5/23/18
to KnockoutJS

@SLG and @Andrew Vickers 
Thanks for the feedback. I will look into implementing a worker thread that does all the computation then assign the array at once. If that does not help then I will provide some code ASAP. 

Noirabys

unread,
May 29, 2018, 2:55:00 AM5/29/18
to KnockoutJS
hi,
is there a documentation or could you explain what  a "descendantsComplete binding event" is ?
var x = ko.observable('');
<div  id="xxx" data-bind="text:x">
   <div  id="yyy" data-bind="text:x">
    </div>
</div>

does a call to x('xxx')  trigger an event on the dom nodes involved ? is it synchronous, or is there an asynchronous mechanism in the background. 
does it mean two events in this example ?

Noirabys

unread,
Jun 11, 2018, 3:27:12 AM6/11/18
to KnockoutJS
hi michael,
it would be great to have an example on how to use the "descendantsComplete" binding event ! 
best regards,
 noirabys


Am Freitag, 18. Mai 2018 05:33:58 UTC+2 schrieb Michael Best:

Michael Best

unread,
Jun 12, 2018, 4:40:04 AM6/12/18
to KnockoutJS
<div data-bind="descendantsComplete: myCallback">

Noirabys

unread,
Jun 15, 2018, 4:16:40 AM6/15/18
to KnockoutJS
hi, 
finally i think i've found a solution which works, but i'm not 100% sure if it's a real solution for all modern browsers.
I've figured out that mutation events fire after rendering, thus this custom binding can be used to react to gui changes (example tracks height changes and requires jquery):

// <div data-bind="afterguichange:{  once: function(h){ console.log('once'+h); }}"> </div> 
ko.bindingHandlers['afterguichange'] = {
    'init': function (element, valueAccessor) {
      var elementsHeight = $(element).height();
      var observer = new MutationObserver(function(mutations) {
      mutations.forEach(function(mutation) {
          var e = $(element);
          if((mutation.type == 'attributes') &&
            mutation.attributeName == 'style'||
            mutation.attributeName == 'class'){
            var hhh =e.height(); 
            if(elementsHeight != hhh){
               if(typeof valueAccessor().once == 'function') valueAccessor().once(hhh);
               elementsHeight = hhh;
            }
          }
        });
     });
     observer.observe(element, { attributes: true, childList: true, characterData: true });
     ko.utils.domNodeDisposal.addDisposeCallback(element, function() {
       observer.disconnect();
     });
   }
}

what do you think about it ? 
best regards,
 noirabys
Reply all
Reply to author
Forward
0 new messages