I have a template image
where I display images. The image display toggles between canvas
and img
tags, depending on if the user just created the image or if it is already on server.
I toogle between img
and canvas
using a reactive dictionary called pageSession
where I store a boolean reactive variable called displayMode
. I have an helper currentDisplayMode
used to return displayMode
value.
So the helper looks like this:
Template.image.helpers({
"currentDisplayMode" : function(){
return pageSession.get ("displayMode");
}
});
and in my template, I load the canvas
or the img
depending on currentDisplayMode
like this:
{{#if currentDisplayMode}}
<img src="{{source}}"width="215" height="215"/>
{{else}}
<canvas id="canvas" width="215" height="215"></canvas>
{{/if}}
1. the problem.
If I try something like this:
pageSession.set("displayMode", false)
var canvas = template.find('#canvas')
//do stuff related to canvas
I can't find my canvas because the UI isn't updated yet.
2. My dirty fix
I use a Meteor.setTimeout()
like this to fix it:
pageSession.set("displayMode", false)
Meteor.setTimeout(function(){
var canvas = template.find('#canvas')
//do stuff related to canvas
}, 100);
3. My question
This fix works so far but I'm worried about cases where 100ms wouldn't be enough to update the UI. Moreover, I don't feel like it is a reliable solution.
Note that it is not just a binary toggle (image or canvas). The canvas need to be re-rendered depending on 3 different modes (identicon, photo, imageFile). Each mode can be re-rendered as well.
To sum it up, I need to fill properly my canvas in several cases (once I make sure it has been rendered before):
- when
displayMode
toogles: from<img>
to<canvas>
- when I fill my canvas with another method: from identicon to photo for instance
- when I fill my canvas with the same method, but different data: e.g. I reload another identicon or I load another photo. How would you proceed?
I tried two other approaches, both by moving the canvas into a dedicated template:
Blaze.render()
the template in a target div and attach to the canvas templaterendered
function my code. It makes it difficult to control what is or what isn't loaded: I need to remove previously rendered canvas templates.- the workaround explained here: Meteor: Forcing rerendering whole template after collection update with Blaze did not work either (I haven't tried hard, it does not look like a clean workaround).
I finally managed to solve this. Basically, what I wanted was to be sure that my canvas was rendered before doing one of my 3 filling tasks (identicon, photo, imageFile).
The first step is the easy one: I use a page Session reactive variable flag
canvasLoaded
that I update on myrendered
anddestroyed
canvas template functions.The second step is something I already used to make sure a file was uploaded (and its url available) on form submit. This is a
waitfor
function I found here : https://stackoverflow.com/a/14811679/3793161So what I do is to wait for my flag
canvasLoaded
to switch to true in thewaitfor
function. In the callback ofwaitfor
I just call aloadCanvas
function where I load the canvas according to the current filling mode and parameters (all stored in reactive dictionary variables).Et voilĂ ! :-)