Search code examples
javascriptjquerymeteormaterialize

Meteor event when template is updated


I am trying to use Materialize with Meteor, and I have hit a bump on how to initialize Materialize javascript, when adding/removing emelents from dom.

Usecase is simple - navbar contains login/register functions when user has not logged in, when she is logged in, there is a dropdown (that requires separate initialization) containing sign out. as rendered on template gets called only once, after second login/logout dropdown stops working.

Template._header.onRendered(function(){
    console.log('onRendered');
    $(".dropdown-button").dropdown();    
});

and html part

<template name="_header">
  <!-- Dropdown Structure -->
  <ul id="dropdown1" class="dropdown-content">
    <li><a href="#!">one</a></li>
    <li><a href="#!">two</a></li>
    <li class="divider"></li>
    <li><a href="#!" data-action="logout"><i class="fa fa-lock left"></i>Sign Out</a></li>
  </ul>
  <nav class="light-blue" role="navigation">
    <div class="nav-wrapper">
      <a href="#!" class="brand-logo">Logo</a>
      <ul id="nav-mobile" class="right hide-on-med-and-down">
        <li><a class="clicker" href="#!">Clicker</a></li>
        {{#if currentUser}}
          <li><a href="{{ pathFor 'welcome' }}">Welcome</a></li>
          <!-- Dropdown Trigger -->
          <li><a class="dropdown-button" href="#!" data-activates="dropdown1">Dropdown<i class="mdi-navigation-arrow-drop-down right"></i></a></li>
        {{else}}
          <li><a href="{{ pathFor 'atSignIn' }}">Sign in</a></li>
          <li><a href="{{ pathFor 'atSignUp' }}">Register</a></li>
        {{/if}}
      </ul>
    </div>
  </nav>

</template>

I have read many questions here and posts in other parts of the interwebs, but I don't understand how to emulate template.updated style callback, that would be called every time element is added, removed or changed within a template. Any ideas?

update: There are very similar question out there. Problem there has different circumstances, but solution is the same - have element in separate template.


Solution

  • Looks like only way are to to wrap the added/removed element in its own nested template, and then listening onRendered there. (As stipulated in this comment)

    Now I have rewritten code like this:

    Template._header_dropdown.onRendered(function(){    
      console.log('onRenderedDropdown');
      $(".dropdown-button").dropdown();  
    });
    

    with html part

    <template name="_header">
    
      <nav class="light-blue" role="navigation">
        <div class="nav-wrapper">
          <a href="#!" class="brand-logo">Logo</a>
          <ul id="nav-mobile" class="right hide-on-med-and-down">
            <li><a class="clicker" href="#!">Clicker</a></li>
            {{#if currentUser}}
              <li><a href="{{ pathFor 'welcome' }}">Welcome</a></li>
              <li><a href="{{ pathFor 'main' }}">Main</a></li>
              <!-- Dropdown Trigger -->
              {{> _header_dropdown}}
            {{else}}
              <li><a href="{{ pathFor 'atSignIn' }}">Sign in</a></li>
              <li><a href="{{ pathFor 'atSignUp' }}">Register</a></li>
            {{/if}}
          </ul>
        </div>
      </nav>
    
    </template>
    
    <template name="_header_dropdown">
      <!-- Dropdown Structure -->
      <ul id="dropdown1" class="dropdown-content">
        <li><a href="#!">one</a></li>
        <li><a href="#!">two</a></li>
        <li class="divider"></li>
        <li><a href="#!" data-action="logout"><i class="fa fa-lock left"></i>Sign Out</a></li>
      </ul>
      <li><a class="dropdown-button" href="#!" data-activates="dropdown1">Dropdown<i class="mdi-navigation-arrow-drop-down right"></i></a></li>
    </template>
    

    and it works. Not very neat solution, but still a lot better than many other leads I had googled. Thanks everybody