admin管理员组文章数量:1295859
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 ponents has been loaded and rendered. It's a rough equivalent of afterRender(), needed for the same mon 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 ponents are loaded, so too early.
<!--ko template: {afterRender: onLoad.bind($data)} -->
- Using the latest 3.3.0-alpha and specifying synchronous:true on all ponents. But I believe since I'm using AMD, the ponents are still 'loaded' asynchronously which mean that just because my root applyBindings() returns, doesn't mean that all ponents have been loaded and rendered.
- Even tried building a collection of deferred objects that get resolved only when their corresponding ponents are loaded. This got overly plicated and still didn't work for reasons I won't go into.
Is there a way to get a callback called once a plete hierarchy of knockoutjs ponents 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 ponents.
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 ponents has been loaded and rendered. It's a rough equivalent of afterRender(), needed for the same mon 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 ponents are loaded, so too early.
<!--ko template: {afterRender: onLoad.bind($data)} -->
- Using the latest 3.3.0-alpha and specifying synchronous:true on all ponents. But I believe since I'm using AMD, the ponents are still 'loaded' asynchronously which mean that just because my root applyBindings() returns, doesn't mean that all ponents have been loaded and rendered.
- Even tried building a collection of deferred objects that get resolved only when their corresponding ponents are loaded. This got overly plicated and still didn't work for reasons I won't go into.
Is there a way to get a callback called once a plete hierarchy of knockoutjs ponents 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 ponents.
- https://github./knockout/knockout/issues/1533
- https://github./knockout/knockout/issues/1475
- Just curious, what does the console.log look like if you echo a "before xx" and "after xx" for each ponent? Perhaps its possible that the nested ponent fires a before/etc event properly, despite "after" not working right? That could be used to manually track when the process is finished. – Andrew Commented Nov 27, 2014 at 4:08
- did you tried this ... data: dataItems will replace the foreach data-bind="template: { name: 'template-name', data: dataItems, afterRender: callbackmethod}" – Hari Darshan Commented Nov 27, 2014 at 10:05
3 Answers
Reset to default 3I've written a knockout library that triggers an event when all ponents have been loaded and bound. It uses reference counting, similar to referencing counting used for garbage collection. I extensively use ponents 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./ericraider33/ko.ponent.loader/wiki
Fiddle: https://jsfiddle/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),
pletedCallback: function (childRef) {
pageModel.loading(false);
childRef.testValue(childRef.testValue()+1);
}
};
var tpRef = ko.ponentLoader.ref.child({ pletedCallback: pageModel.pletedCallback});
var tpModel = {
attached: function(element) { return tpRef; },
testValue: ko.observable(5)
};
ko.ponents.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.ponentLoader.setOptions({ verbose: true });
ko.applyBindings(pageModel, $('#ko-div')[0]);
Here is what worked for me. I did not try it in all possible variations such as mixing sync and async ponents, or using custom ponent loaders.
There is a method in KO 3.3.0 that all ponents loading goes through:
ko.ponents = { get: function(ponentName, callback) { ...
the get
method is invoked with a desired ponentName
and when ponent has been loaded - a callback
is invoked.
So all you need to do is wrap ko.ponents.get
and callback
and increment pendingComponentsCount
on each call, and decrement it after callback
is executed. When count reaches zero it means that all ponents were loaded.
25 lines of JS code (using underscorejs).
You also need to handle a special case where ko.applyBindings
did not encounter any ponents, in which it also means that all ponents (all zero of them) were loaded.
Again, not sure if this works in every situation, but it seems to be working in my case. I can think of few scenarios where this can easily break (for example if somebody would cache a reference to ko.ponents.get
before you get to wrap it).
If you'r working with ko.ponents this might be of use:
1) Create a deferred object to keep track of each ponent loading
var statusX = $.Deferred()
var statusY = $.Deferred()
2) Inform knockout to tell you when the ponent is loaded and ready
ko.ponents.get('x-ponent', statusX.resolve) //Note: not calling resolve, but passing the function
ko.ponents.get('y-ponent', statusY.resolve)
3) Synch up both status deferreds
$.when(statusX.promise(), statusY.promise())
.done( function allComponentsLoaded(ponentX, ponentY){
//Both ponents are ready here
//Note the arguments from the function es via
//ko->jquery deferred resolve
});
版权声明:本文标题:javascript - KnockoutJS afterRender callback when all nested Components have been rendered? - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1741603540a2387840.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论