Meteor Guide: Blaze

This is the comment thread for an article in the Meteor Guide.

Read the article: http://guide.meteor.com/blaze.html

The comment thread for each article appears at the very bottom of the page. Use this thread to post:

  1. Interesting articles related to the content
  2. New ways to do things that aren’t covered in the Guide
  3. Suggestions for Guide improvements

Or anything else related to this topic that people could find useful!

Each and With There are also two Spacebars built-in helpers, {{#each}}, and {{#with}}, which we do not recommend using (see use each-in below). These block helpers change the data context within a template, which can be difficult to reason about.

How about this case? (we care about <ul>):

      +with games
        ul
          +each game in this
            li {{game.name}}
      else
        | Not Found

or we have strange code without {{#with}} :slight_smile:

      +let tmp_games=games
        +if tmp_games
          ul
            +each game in tmp_games
              li {{game.name}}
        else
          | Not Found
 

One Blaze pattern that I am very fond of is ditching helpers and storing everything on the template instance. In onCreated:

Template.templateName.onCreated(function() {
  let tpl = this;

  _.extend(tpl, {

    someState: new ReactiveVar([], EJSON.equals),

    initialize(params) {
      // do whatever initialization e.g.:
      tpl.listenForChanges();
    },

    listenForChanges() {
      tpl.autorun(comp => ...);
    },

    useThisInsteadOfHelper(arg1, arg2) {

     },

  }).initialize(tpl.data);
});

Then if you declare a global helper:

Template.registerHelper('$tpl', function () {
  return Template.instance();
});

You can do {{$tpl.useThisInsteadOfHelper arg1 arg2}} or {{$tpl.someState.get}} inside of the templateName html file. This means that your functions can call each other, store state on the template instance without calling Template.instance() everywhere, and aren’t run everytime anything in the data context changes (if you want the function to rerun whenever anything in the data context changes you have to explicitly call Template.currentData()). This gives waaaay more flexibility.

1 Like

I have elegant bicycle for store state:

You have clicked the button {{state.counter}} times.
<button>click</button>
Template2 'hello',
  states: counter: 0
  events: 'click button': ->
    # increment the counter when button is clicked
    @state.counter += 1

You still need {{#with ... }} to switch the context to the looped item for accessing it from an event and don’t want to write another template for it:

{{#each user in users}}
    {{ user.name }}
    {{#with user=user }}
        <span class="remove">X</span>
    {{/with}}
{{/each}}

Template.users.events({
    'click .remove': function(event) {
        console.log(this);
    }
});

Using the {{#with }} wrapper console.log will return {user: {name: ... }}; without it it will return {users: [{name: ...}]} and you won’t know which user from the list you clicked on.

Is there a way to add the user to the context with {{#let }} instead? The other way I found to do it is add a data attribute to the span an retrieve it from the event.target.dataset but then it turns into a string and feels wrong. Sometimes I still need access to other objects from the outer context and then it turns into a monstrous {{#with user=user users=users foo=foo }}.

Thanks! It is better. But we need define new variable:

      +with tmp_games=games
        ul
          +each game in tmp_games
            li {{game.name}}
      else
        | Not Found

Because helper games called twice in this case:

      +with games=games
        ul
          +each game in games
            li {{game.name}}
      else
        | Not Found