DeBraid
DeBraid

Reputation: 9451

Reactive Meteor Templates and Deps Dependency -- update a template when another changes or is re/rendered

Problem: Meteor JS app with 2 distinct templates that need to share some data.

They are dependent on one another, since I aim to extract text (Step 1) from one, and then create dynamic buttons (Step 2) in another template. The content of the buttons is dependent on the table.

buttons.html

<template name="buttons">

   {{#each dynamicButtons }}
    <button id="{{ name }}">{{ name }}</button>
  {{/each}}

</template>

My goal is for the name property to come from the content of reactiveTable.html (see above, or their Github page, package meteor add aslagle:reactive-table.

These need to be dynamically linked since table re-renders constantly w/ different group of products, which are linked up through Template.reactiveTable and a specific data context (Pub/Sub pattern).

IF the table is (re)rendered, then parse it's content and extract text. Once the table is parsed, dynamically inject newly created buttons into the UI. Note UI.insert takes two arguments, the Object to insert, and then location (DOM node to render it in).

Template.reactiveTable.rendered = function () {
    UI.insert( UI.render( Template.buttons ) , $('.reactive-table-filter').get(0) )
};

(Insert new buttons every time a reactiveTable is rendered.)

This code works, but is flawed since I cannot grab the newly rendered content from reactiveTable. As shown in this related question, using ReactiveDict package:

Template.buttons.helpers({
  dynamicButtons: function() {
    var words = UI._templateInstance().state.get('words');
    return _.map(words, function(word) {
      return {name: word};
    });
  }
});

Template.buttons.rendered = function() {

  // won't work w/ $('.reactiveTable) since table not rendered yet, BUT  
  // using $('h1') grabs content and successfully rendered dynamicButtons!

  var words = $('h1').map(function() { 
    return $(this).text();             
  });
  this.state.set('words', _.uniq(words));
};

Template.buttons.created = function() {
  this.state = new ReactiveDict;
};

How can I change my selector to extract content from Template.reactiveTable every time is re-renders to create buttons dynamically? Thanks.

Upvotes: 2

Views: 564

Answers (1)

Geoffrey Booth
Geoffrey Booth

Reputation: 7366

You’re using a lot of undocumented functions in there, and UI.insert and UI.render which are bad practice. The just-released Meteor 0.9.1 eliminates them, in fact.

Create your dynamic buttons the Meteoric way: by making them dependent on a reactive resource. For example, a Session variable. (You could also use a client-side-only collection if you want.)

Template.reactiveTable.rendered = function () {
  // Get words from wherever that data comes from
  Session.set('buttons', words);
};

Template.buttons.helpers({
  dynamicButtons: function() {
    if (Session.equals('buttons', null))
      return [];
    else
      return _.map(Session.get('buttons'), function(word) {
        return {name: word};
      });
  }
});

Every time reactiveTable is rendered or rerendered, the buttons Session variable will update. And because your dynamic buttons are depending on it, and since Session variables are a reactive resource, the buttons will rerender automatically to reflect the changes.

Upvotes: 1

Related Questions