I don’t think I’ve quite wrapped my head around the nature of relating pages in Mateor. One example that is confounding me is reloading a page that has Neo Reveal js in. I don’t have any problem with this page when I load the app from the home page, but I simply get a failure when I reload the page that contains reveal. I get the following output, which I think means that the event handlers aren’t being released (perhaps)? I’ve seen a similar issue with jQuery, however I think this is specific to Reveal and how it interfaces with Meteor.
Any help would be appreciated. Even in the least, understanding why some pages load properly when loading from the home page, while they do not load properly when reloaded.
Thanks (here’s the error message):
Exception from Tracker afterFlush function:
meteor.js?hash=e3f53db…:930 TypeError: Cannot read property 'querySelectorAll' of undefined
at slide (neo_reveal-js.js?hash=0c1084f…:1552)
at readURL (neo_reveal-js.js?hash=0c1084f…:2231)
at start (neo_reveal-js.js?hash=0c1084f…:362)
at proceed (neo_reveal-js.js?hash=0c1084f…:302)
at load (neo_reveal-js.js?hash=0c1084f…:341)
at Object.initialize (neo_reveal-js.js?hash=0c1084f…:250)
at Blaze.TemplateInstance.<anonymous> (story.js:63)
at blaze.js?hash=813922c…:3397
at Function.Template._withTemplateInstanceFunc (blaze.js?hash=813922c…:3743)
at fireCallbacks (blaze.js?hash=813922c…:3393)
My feeling is that it’s to do with the template not being ready before Neo Reveal is triggered, but we really need to see your template and code.
I’m not sure if it’s best to put all my code (lotsa code) in here or just the basics to start off with. Let’s go with the basics.
I think I’ve read conflicting reports on how onRendered and domReady are effectively the same thing. I’ve asked that question on this forum before, but haven’t really had a satisfactory answer. Having to add timeout to jquery ready, and other functions suggests that they’re not the same thing, and it doesn’t seem like adding a timeout is a particularly good solution dealing with loading. I would think this is along the same vein of questioning.
In any event, here’s the code. I can provide more with the other Reveal events, but thought I’d start simple.
/* Story rendered */
Template.story.onRendered(function(){
// initialize
Reveal.initialize({
width: "100%",
height: "100%",
margin: 0,
minScale: 1,
maxScale: 1,
controls: false,
progress: true,
slideNumber: false,
history: false,
keyboard: true,
overview: false,
center: false,
touch: true,
fragments: true,
embedded: false,
autoSlide: 0,
autoSlideStoppable: true,
autoSlideMethod: Reveal.navigateNext,
mouseWheel: true,
hideAddressBar: true,
transition: 'slide', // none/fade/slide/convex/concave/zoom
transitionSpeed: 'default', // default/fast/slow
backgroundTransition: 'slide', // none/fade/slide/convex/concave/zoom
viewDistance: 2,
});
Here’s my answer. Template.xxx.onRendered
is run as soon as all non-reactive parts of the DOM are ready, unless those reactive parts are available immediately. So, taking this template as an example:
<template name="xxx">
<h1>Here's some stuff I found</h1>
{{#each thing in stuff}}
<div>{{thing.a}}, {{thing.b}}
{{/each}}
<p>Hope that's useful</p>
</template>
The onRendered
is typically run here:
<h1>Here's some stuff I found</h1>
<p>Hope that's useful</p>
So, the more complex and all-eggs-in-one-basket the template, the less likely it is to be as you expect when onRendered
runs. In your case (you didn’t show your template) it should be something like this:
<template name="story">
<div class="reveal">
<div class="slides">
{{some-content-goes-here}}
</div>
</div>
</template>
The trick then is to make sure that the reactive content is available when the template is rendered. In Blaze, that would typically be done in the parent of story
with something like:
{{#if Template.subscriptionsReady}}
{{> story}}
{{/if}}
In other words, don’t even try to render the story
template until the subscription which is being used to populate it is ready. Then, when Template.story.onRendered
runs you know the DOM will be in a known, good state.
Hope that helps 
My bad, I should have posted the HTML. Does this look totally off base?
<template name="story">
{{#if Template.subscriptionsReady}}
<span id="pageStory">
<div class="flex-container">
<a class="btn-floating btn-large waves-effect waves-light black" id="play"><i class="material-icons">play_arrow</i></a>
</div>
<div id="page-number">
<div class="chip"></div>
</div>
{{#each audio in audios}}
<audio id="{{audio.id}}" class="{{audio.class}}" {{audio.autoplay}} {{audio.loop}} preload="none">
<source src="{{audio.file}}" type="audio/mp3"/>
</audio>
{{/each}}
<div class="reveal" id="reveal">
<div class="slides" id="slides">
Yeah - that’s highly likely to fire onRendered
too soon. Putting the {{#if Template.subscriptionsReady}}
in the template means the empty template is added into the DOM and onRendered
is fired.
BTW: I just noticed I forgot the Template.
before subscriptionsReady
in my example. Sorry - now corrected.
Oh, I see. Ok, can I run like this?
{{#if Template.subscriptionsReady}}
<template name="story">...</template>
{{/if}}
No - it’s done as I indicated from the parent template:
Gotcha. Let me give this a try.