简体   繁体   中英

Set the return value of Meteor JS Helper, inject this dynamically into template

EDIT:

Given the answers below, using Meteor Deps seems like the ideal play since I want to share data between two distinct templates, and it should be reactive to any changes that occur.

To clarify: source of my data is Template.reactiveTable and the destination is Template.buttons . When the data in reactiveTable changes, I want the buttons to reflect this.

END EDIT

I am looking to set the value of buttons based on the content of a table (specifically, the <h1> values).

buttons.html:

  <template name="buttons">
    {{#each testButtons }}
       <button id="{{ name }}">{{ name }}</button>
    {{/each}}
  </template>

With this hard-coded it works as expected (two buttons render labeled Alice and Bob

UI.registerHelper('testButtons', function () {
        return [ 
          { name: "Alice" }, 
          { name: "Bob" } 
        ]
    }
)

The template happily accepts and renders this array of objects . However, NOT when I generate the array of objects dynamically.

Goal: for each unique word contained within my h1 tags, generate a button (almost like a blog tags).

By replacing my helper code with snippet below (using jquery parsing <h1> tags, generate array to send to template).

Assume html is:

  <h1>foo</h1>
  <h1>bar</h1>
  <h1>baz</h1>

then run snippet below in console, will create uniqStrings = [ "foo", "bar", "baz"]; as desired.

$( 'h1' ).map(function () {
  var words = [];
  words.push($(this).text());
  uniqStrings = _.uniq(words);

});

How do I then send uniqStrings back to my buttons template to render n= uniqStrings.length buttons? Thanks!

Assuming this html:

<body>
  <h1>Alice</h1>
  <h1>Bob</h1>
  {{> buttons}}
</body>

<template name="buttons">
  {{#each testButtons }}
    <button id="{{ name }}">{{ name }}</button>
  {{/each}}
</template>

You can get it to work with this implementation:

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

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

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

Note you will need to do: meteor add reactive-dict

When the buttons template is created is initializes its own internal reactive state. After it is rendered, it fills that state with the text from all of the h1 tags on the page. Because that state is reactive, it will then cause the testButtons to run and return the correctly formatted data to your template. Please see my post on Scoped Reactivity for more details.

Because the buttons template uses scoped reactivity, it can be used as many times as you like on any page without modification to the parent template.

Whilst it's not totally clear to me why you're trying to parse the content of a table and then render it in another table (this is what you're trying to do, isn't it?), the basic principle is as follows:

Your template will rerender when any of its reactive dependencies change. So that means that you need to either:

  • store the array in question in a structure which is reactive by design (so either the minimongo , ie the client side database), or else a Session variable .
  • use a separate (reactive) variable which just tells the template it needs to rerender at the right times.

The latter is probably less good from the perspective of app structure, but easiest to exemplify:

var renderDep = new Deps.Dependency(),
    words = [];

UI.registerHelper('testButtons', function () {
    renderDep.depend();
    return words;
});

And then whenever you call:

$( 'h1' ).map(function () {
    words = [];
    words.push($(this).text());
    uniqStrings = _.uniq(words);       
});  

Make sure you call:

renderDep.changed();

immediately afterwards, and all its dependencies (ie the template helper) will rerun and return the new words content.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM