Reputation: 35194
I have a knockout component which looks something like this:
define(['knockout', 'text!./my-component.html', 'pubsub'], function(ko, htmlString, pubsub) {
function viewModel(params) { }
return {
viewModel: {
createViewModel: function(params, componentInfo) {
var vm = new viewModel(params);
pubsub('updateViewModel').subscribe(function(){
// update vm
});
return vm;
}
},
template: htmlString
};
});
I use the createViewModel
function to subscribe to an update event, which I use later on to trigger an update of the components viewmodel from other components.
I include the compnent on my page like this:
<!-- ko component: "my-component" -->
<!-- /ko -->
What I would like some verification on is the load order of things. I want to be sure that the createViewModel
has been invoked before I might trigger the event.
This is my current order of calls:
// register my-component here
ko.applyBindings(myMainViewModel);
// code that might trigger the component update event here
I've read that ko.applyBindings
is sychronous. But does that also include an implicit applybindings
to all registered components, like my-component
above? Do I need to set the synchronous
property to true
on the component in order to achieve this? If I understand it correctly, that flag is only related to rendering.
What I want to avoid is a race condition where I trigger the update event before it has been subscribed.
Upvotes: 0
Views: 426
Reputation: 3256
ko.applyBindings can act synchronously if the following conditions are satisfied BEFORE calling:
Its when the component viewmodel and templates are not in memory that applyBindings becomes async (event if you set the synchronous=true).
This synchronous flag comes in to play in applybindings from the component binding. Notice that component binding does a ko.components.get
call and passes a call back which will render the component on the DOM.
knockout/src/components/loaderRegistry.js has the definition of ko.components.get. The synchronous flag says that if the component is already cached (in memory) DON'T relinquish control of the thread. Its only when you release control of the thread (setTimeout, DOM insert/wait, ..) that applyBindings will return.
The only thing I'm not too sure about is how RequireJS will interact in here. There is code in knockout which will try to resolve the component using require first.
In any case the following steps will bring you closer (NOT PERFECT. See notes bellow)
//Load component vm, template and register it with synchronous=true
ko.appplyBinding(....)
ko.components.get("my-component" , function() {
//trigger component update event
})
There are few problems with this, and there are solutions to all of them.
Need to wait for multiple components to finish loading
[to solve this you can create a promise array for each component and resolve each of them via ko.components.get. Finally you can $.when(mypromiseArray, myCallback) to synch up all the promises]
ko.component.get does NOT tell you when the component is finally rendered on the DOM.
This is a much more challenging problem. I will share the solution if you need this level of precision (you need to know with in 50ms of when the component is loaded, and rendered on the UI).
Upvotes: 2