KnockoutJS afterRender callback when all nested Components have been rendered?

javascript, knockout-components, knockout.js

Solution

I've written a knockout library that triggers an event when all components have been loaded and bound. It uses reference counting, similar to referencing counting used for garbage collection. I extensively use components in my project(s), including nesting many levels deep, and I can't live without knowing when everything is "ready to go". I haven't spend much time on documentation of usage, but the basics are there.

Git Hub wiki: https://github.com/ericraider33/ko.component.loader/wiki

Fiddle: https://jsfiddle.net/ericeschenbach/487hp5zf/embedded/result/

Usage HTML:

<div id="ko-div">
  Status: <span data-bind="text: loading() ? 'Loading' : 'Done'"></span>
  <br><br>
  <test-panel></test-panel>
</div>

Usage JS:

var pageModel = { 
  loading: ko.observable(true), 
    completedCallback: function (childRef) { 
    pageModel.loading(false); 
    childRef.testValue(childRef.testValue()+1);  
  }
};

var tpRef = ko.componentLoader.ref.child({ completedCallback: pageModel.completedCallback});
var tpModel = { 
  attached: function(element) { return tpRef; },
  testValue: ko.observable(5)
};

ko.components.register('test-panel', {
    viewModel: function() { return tpModel; },
    template: '<div data-bind="attached: true">Test Panel<br>From Code <span data-bind="text: testValue"></span></div>'
});


ko.componentLoader.setOptions({ verbose: true });
ko.applyBindings(pageModel, $('#ko-div')[0]);

Problem

I have a hierarchy of nested KnockoutJS Components using 3.2.0. It's working very well but I'm looking to execute some code once my entire hierarchy of components has been loaded and rendered. It's a rough equivalent of afterRender(), needed for the same common uses cases as afterRender. I've tried a few approaches but no luck so far: - Added the following to the root template but it gets called before the nested components are loaded, so too early. ` <!--ko template: {afterRender: onLoad.bind($data)} --> ` - Using the latest 3.3.0-alpha and specifying synchronous:true on all components. But I believe since I'm using AMD, the components are still 'loaded' asynchronously which mean that just because my root applyBindings() returns, doesn't mean that all components have been loaded and rendered. - Even tried building a collection of deferred objects that get resolved only when their corresponding components are loaded. This got overly complicated and still didn't work for reasons I won't go into. Is there a way to get a callback called once a complete hierarchy of knockoutjs components have been loaded and rendered? Thanks! I just came across these two threads so it seems others are looking for this as well. The key differentiator from the existing workarounds are they don't work with nested components. - https://github.com/knockout/knockout/issues/1533 - https://github.com/knockout/knockout/issues/1475

Original source