Neo Reveal JS Error on Reload

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 :slight_smile:

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.