Meteor nested template bug 1.1.0.2?


#1

Finding a way to initialize a jquery component, on ALL nested templates, is surprisingly tricky. Outside Meteor this would otherwise be a simple $( document ).ready().

See DEMO of the problem here

See the code here:

One would expect layout.rendered to initialize everything in the sub/nested templates:

HTML:

 <template name="layout"> 
   <body>
   {{> ideal}}
  </body>
 </template>

 <template name="ideal"> 
  <div class="component"></div>
 </template>

JS:

 Template.layout.rendered = function(){ 
//or alternatively Template.body.rendered()
  $('ul.tabs').tabs() 
  }
}

The component in {{> ideal}} will not initialize if you navigate to it with Iron Router, for example. It only initializes on hard page refresh (because template layout is rendered).

So instead you would have to initialize on each template that element will be used

Template.ideal.rendered ...

Template.x.rendered ...

Template.y.rendered ...

Another solution is putting a 0ms timer on Routes.onAfterAction, but that seems inelegant.

Router.onAfterAction(function() {
  setTimeout(function() {
    $('.layout-yield ul.tabs').tabs();
  }, 0);
});

Am I missing something in the Docs? Or is this a bug / edge case? IMHO this should be straightforward.


#2

To add to this. We’ve tried iron-router events:

onRun
onBeforeAction
onAfterAction

All of these seem to happen before the route’s template content is present. I noticed that onBeforeAction required a call to next() to go on, I even tried looking for the DOM content after the next call.

I also tried rewriting our routes like this:

Router.route('someRoute', function() {
  this.render('someRoute');
  // look for DOM content, still not found
});

#3

Update: Meteor.defer() has been suggested but it isn’t any different than setTimeout, as far I can see.


#4

It’s very hacky, butt ugly, and not sure if it works for you and Materialize CSS, but what worked for me a couple times messing with Isotope is just putting it in the template:

<template name="someTemplate">
    {{#if Template.subscriptionsReady}}
        the html you want to use and have the script work on
        <script>
            the jquery init function
        </script>
    {{#/if}}
</template>

#5

Thanks @camiel

Would like @debergalis opinion here.

Seem’s a bit strange that we would have to resort to hacks like this. Especially for something as basic as $( document ).ready()

The more time that passes without an obvious answer, the more I think this is an omission by Iron Router, or Meteor. Any other solutions out there?


#6

Bumping this. No answer on Stackoverflow either.


#7

Just ran into this issue myself. I hope there is a non-hacky answer out there. Seems like it should be a simple thing. I hope this issue does not turn into a deal-breaker for materialize CSS.


#8

Just to document further:
Some people suggested UI.body.rendered()
Though this will fail. Even with a timeout.
Still perplexed there is not way to do the equivalent of: on document ready.


#9

I just got materialize CSS’s dropdowns working with this package - aldeed:template-extension and this code:

Template.onRendered(function () {

// Initialize all datepicker inputs whenever any template is rendered
this.$(’.datepicker’).datepicker();
});

Might be the ticket


#10

@stewartellis
This is what we ended up doing, but I consider it a hack. Looking for a
better way.

Router.onAfterAction(function() {
setTimeout(function() {
//whatever needs every template and nested template loaded.
$(‘ul.tabs’).tabs();
}, 0);
});

Lucas Geiger


#11

@stewartellis see also this pos I just made:

Lucas Geiger