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