When is it safe to call the find(...) method on a ractive instance and be guaranteed that the template has been rendered and the DOM elements are available?
Background:
I'm new to RactiveJS, building my first application with it. I've been instantiating Ractive instances and then calling methods like find() on those instances to access elements rendered from my templates. Something like this:
var ractive = new Ractive({ el: ..., template: ..., data: ..., etc });
var element = ractive.find('.some-template-element');
This has been working fine so far, but I'm wondering whether I might have a race condition here because of the fact that ractive seems to render templates asynchronously. Is it safe to write code like the above or do I need to instead move everything into callbacks like this?
ractive.on('complete', function() {
var element = ractive.find('.some-template-element');
});
Too Much Information:
In practice, of course, what I'm doing is more complicated than this simple pseudo-code. I'm creating 'widgets' that use Ractive as an internal implementation detail. Right now, I create those widgets and then start calling methods on them. But if the Ractive methods aren't ready to call right away, I'll need to restructure my widgets to expose callbacks/promises that get called once I know my ractives have been created and are ready for use.
I haven't been able to find details in the RactiveJS documentation that explain when it's safe to call the various functions on Ractive, but I'm hoping I've just missed something.
Assuming you've provided an el
option, rendering happens synchronously with the new Ractive
instantiation.
While you can subscribe via ractive.on( 'event', ... )
, it is often handy and cognitively easier to use the onevent
options:
var log = [];
var r = new Ractive({
el: document.body,
template: '#template',
data: {
log: log
},
components: {
'child-component': Ractive.extend({
template: '<span>child</span>',
oninit: function() {
log.push('child component init');
},
onrender: function() {
var span = this.find('span');
log.push('child component render find span:' + !!span);
},
oncomplete: function() {
log.push('child component complete');
}
})
},
oninit: function() {
log.push('parent view init');
},
onrender: function() {
var div = this.find('div'),
span = this.find('span');
log.push('parent component render, find div: ' + !!div + ' find span: ' + !!span);
},
oncomplete: function() {
log.push('parent component complete');
}
});
// these won't fire becasue they already happened!
r.on('init', function() {
log.push('view on("init"...)');
});
r.on('render', function() {
log.push('view on("render"...)');
});
// this will fire because complete is always async.
r.on('complete', function() {
log.push('view on("complete"...)');
});
<script src='//cdn.jsdelivr.net/ractive/0.7.3/ractive-legacy.min.js'></script>
<script src='//cdn.jsdelivr.net/ractive.transitions-fade/0.2.1/ractive-transitions-fade.min.js'></script>
<script id='template' type='text/ractive'>
<div intro='fade'>main view</div>
<child-component/>{{#log}}
<li>{{.}} {{/}}
</script>