Meteor stopped running template `rendered` functions

Im trying to run some jquery code after the template renders. But it’s not working. When I run the code in the console manually, it works. Here’s the js :

Template.PanelLayout.helpers({
    restricted: function() {
        return !Meteor.user();
    },
    authInProcess: function() {
        return Meteor.loggingIn();
    },
    canShow: function() {
        return !!Meteor.user();
    }
});

Template.PanelLayout.rendered = function() {
    $(document).ready(function() { // This is the code I want to run
        $(".button-collapse").sideNav();
        $('.collapsible').collapsible();
    });
}

Template code :

<template name="PanelLayout">
    {{#if restricted}}
        {{> NotFound}}
    {{else}}
        {{#if authInProcess}}
            {{> spinner}}
        {{else}}
            {{#if canShow}}
                <header>
                    {{> PanelMainNav}}
                </header>
                <main id="panel-content">
                    {{> Template.dynamic template=content }}
                </main>
            {{/if}}
        {{/if}}
    {{/if}}
</template>

Im not sure but I think it’s because I have added the if else statements to load the content only when the user is logged in? How can I fix this?

3 thoughts -

  1. the rendered function is deprecated, use the onRendered callback

  2. don’t wrap your code in a $(document).ready() method - it will never get triggered - Meteor is a single page app, the document was ready some time before your template came to be rendered

  3. put your jQuery into into a 0 ms timeout, or the undocumented Meteor.defer(), both of which will actually do your jQ when meteor is ready and are slightly different implementations of the same thing, with the latter maybe more efficient

    Template.PanelLayout.onRendered( function() {
    Meteor.setTimeout( function() {
    $(".button-collapse").sideNav();
    $(’.collapsible’).collapsible();
    }, 0);
    });

or

Template.PanelLayout.onRendered(function() {

    Meteor.defer( function() {
        $(".button-collapse").sideNav();
        $('.collapsible').collapsible();
    });
});

That should make the jQuery work

1 Like

Perfect. Now it’s working. Thanks :slight_smile: I also have another code like that. It loads without an issue. But when I visit a different page and go again to that page it doesn’t load the code. That code turn the textarea to a wysiwyg editor (TinyMCE). On the first load it works but then the editor is gone. HEre’s the code :

Template.PanelLayout.onRendered(function() {
    this.autorun(function() {
        if (ready.get()) {
            page = Pages.findOne({
                slug: 'about'
            });
            tinymce.init({
                selector: "#pageContent",
                height: 400
            });
            tinymce.get('pageContent').setContent(page.content);
        }
    });
});

Check out Tracker.afterflush, which worked for me

http://docs.meteor.com/#/full/tracker_afterflush

Sorry it didn’t work for me :disappointed_relieved:

Do you call other templates from with in the template your onRendered is attached to?

No I use only quickForm in there. But that template is loaded as a dynamic template from another parent template. Will that be a problem?

Not a problem per se, but will affect what is really rendered when your template onRendered fires.

Oh. Thanks. Any suggestions to fix it?

I would do it more like this:

Template.PanelLayout.helpers({
    restricted: function() {
        return !Meteor.user();
    },
    authInProcess: function() {
        return Meteor.loggingIn();
    },
    canShow: function() {
        return !!Meteor.user();
    }
});

Template.InnerLayout.onRendered({
        $(".button-collapse").sideNav();
        $('.collapsible').collapsible();
});

Template Code

<template name="PanelLayout">
        {{#if restricted}}
            {{> NotFound}}
        {{else}}
            {{#if authInProcess}}
                {{> spinner}}
            {{else}}
                {{#if canShow}}
                    {{>InnerLayout}}
                {{/if}}
            {{/if}}
        {{/if}}
</template>
<template name="InnerLayout">
       <header>
             {{> PanelMainNav}}
       </header>
       <main id="panel-content">
             {{> Template.dynamic template=content }}
       </main>
 </template>

IIRC, onRendered isn’t called every time an {{#if}} is reevaluated. I would have to check on that. With this, you know that the elements that jQuery is looking for will be present when the onRendered is called.

Great. For that case this is a good idea. But for the next case it’s not. In my second code, the element Im trying to change through jquery is inside the content. Can’t take it out.

Just found out that sometimes this work. But sometimes it does not. Any clue?

Just found out that adding onRendered to a dynamic layout breaks the onRendered in the main layout!

So can you share what is your solution? :slight_smile:

Ok nevermind, ive fixed it. onRendered declaration is working you just need to always refresh the tinyMCE, to do that you have to put tinymce.remove(’#note_field’); before your tinyMCE initializer. So the declaration must look like.

tinymce.remove('#note_field');
    tinymce.init({
      selector: '#note_field',
      skin_url: '/packages/teamon_tinymce/skins/lightgray',
      height : "300"
    });