Can't access jQuery objects within onRendered

Read my reply:

The common way to address this specific use case is by using a helper. In the example below I’ve used a Session variable, as this is what you say you are using, although in practice a template ReactiveVar would probably be a better choice.

Sorry about that. I read the code not the full post xD

If I don’t have subscriptions.
So it still don’t work for all above comments.

Template.productDetail.onRendered(function () {
       // don't have sub
        console.log(this.$('.prod-detail-name'));
});

Please help me. have any solution?

Just for everyone in the future still having issues with accessing reactive elements.

My use case:

  • Generate a list
  • Make a checkbox to a bootstrap toggle box

When i tried to get the reactive element after the onRendered or the subscriptionsReady hook i could create bootstrap toggle boxes just for the first time accesing the site. when i changed the routes it did not show the bootstrap toggle boxes anymore. Only on the first time i visited that page.
The problem is that the toggle boxes may get rerendered via the subscription but the hooks do not get called again.

Never the less i solved my problem by displaying the subscription data with blaze and after the block where it is inserted i make a little tag in which i create the toggle box. that way i ensure that even if it gets reloaded a toggle box will be recreated.

{{#each elements}}
    <tr>
        <td>{{this._id}}</td>
        <td><input type="text" id="{{this._id}}" value="{{this.name}}"></td>
        <td><input
                    data-on="public"
                    data-off="private"
                    class="form-control publicPrivateToggle"
                    type="checkbox"
                    data-toggle="toggle"
                    data-class="fast"
                    id="publicPrivateToggle_{{this._id}}"
                {{setChecked this.public}}
            ></td>
        <script>
            this.$('#publicPrivateToggle_{{this._id}}').bootstrapToggle({
                width: '100%'
            });
        </script>
    </tr>
{{/each}}

So revisiting this…

This aspect of Blaze has always flummoxed me! It turns out it was my use of Template.subscriptionsReady() that was my real problem, <template>.onRendered works as advertised.

@jamgold came up with a hacky workaround that I did not really grok on first read:

Same problem. Your Template.productDetail.onRendered fires when the template gets rendered, which is most likely before Template.subscriptionsReady

In the part where you have …display product… you could just call another template and attach the onRendered to that.

So I will be very pedantic. What he is saying is this:

@jamgold’s Hacky workaround

foo.html:

<template name="parent"> 
{{#if Template.subscriptionsReady}}
  <div id="firstDiv"></div>
  {{> childHack}}
{{/if}}
</template>

<!-- childHack template can be empty -->
<template name="childHack"></template>

foo.js:

Template.parent.onRendered(function parentOnRendered() {
  console.log($('#firstDiv').length);  // What?? it is 0, nothing found!!
  // Nothing is found because Template.subscriptionsReady() is false,
  // parent template is successfully rendered with no HTML.
});

Template.childHack.onRendered(function childHackOnRendered() {
  console.log($('#firstDiv').length);  // Hey it is 1, gotcha!
  // this template will only be rendered when Template.subscriptionsReady()
  // is true & the parent template completed rendering its HTML with data
});

Even if this is hacky, it is relatively simple & elegant for handling the cases when you use Template.subscriptionsReady().

THANKS @jamgold!

========== EDIT ==========

Right after posting this I had another thought. And fell upon @mrzafod’s solution. Without the childHack template you can do this:

@mrzafod’s elegant solution

foo.js:

Template.parent.onRendered(function parentOnRendered() {
  console.log('found1?: ', $('#firstDiv').length);  // 0, nothing found
  // Nothing is found because Template.subscriptionsReady() is false,
  // parent template is successfully rendered with no HTML.
  let initialized = false;
  template.autorun( () => {
    if(!initialized && template.subscriptionsReady()) {
      // Subscriptions are now ready, the template is rendering
      console.log('found2?: ', $('#userprofile-modal').length);  // 0, nothing found
      // Nothing is found, because we are still rendering templates
      initialized = true;
      Tracker.afterFlush(() => {
        // Reactivity computations have finished
        console.log('found3?: ', $('#userprofile-modal').length);  // 1
        //  Now the DOM is populated with the template HTML
      });
  });
});

Thanks @mrzafod !!