Using different variables with the same name in different templates

I have two templates, which are included into some layout template:

{{>b_afisha_today}}
{{>b_afisha_soon}}

I want to use some variable in helpers for one of my templates.

Template.b_afisha_today.onCreated(function() {
    this.data.day = new Date().getDate();
}

Template.b_afisha_today.helpers({
    times: function() {
      var day = Template.instance().data.day;
    }
})

The problem here is that Template.instance().data.day is now belongs to the parent layout template (and to the global scope I guess). So, if I initialize a new variable with the same name in my second template, it will change everything in my first template.

Template.b_afisha_soon.onCreated(function() {
    this.data.day = 'mess everything';
}

Not sure if it is possible to use two independant variables with the same name, each is accessable within one template?

1 Like

I can ask question in another way.

Template.one.onCreated(function() {
    this.data.message = 'Template two should not see me, but it does';
}

Template.two.helpers({
    test: function() {
        return Template.instance().data.test;
        // returns 'Template two should not see me, but it does'
    }
});

Why is it possible?

If you don’t explicitly set a data context when calling a template, The context will be inherited from the parent.

You need to explicitly pass an empty context as noted in the Meteor guide:

Additionally, for better clarity, always explicitly provide a data context to an inclusion rather than letting it inherit the context of the template where it was rendered:

<!-- bad: inherits data context, who knows what is in there! -->
{{> myTemplate}}

<!-- explicitly passes empty data context -->
{{> myTemplate ""}}

Nice technique. Thanks. The problem here is that if I call a template with empty context, I also can’t set its data in the future.

HTML:

{{> myTemplate ""}}

JS:

Template. myTemplate.onCreated(function() {
    this.data.x = 1;
    console.log(Template.instance().data.x); // undefined
});

I found out that the following approach can satisfy me. Are there any hidden problems with it?

Template.myTemplate.onCreated(function() {
  var t = Template.myTemplate;
  t.variable = 1;
});

Template.myTemplate.helpers({
  var t = Template.myTemplate;
  console.log(t.variable);
});

A potential problem I see is if you use the template more than once at a time, both instances will be accessing the same variable, to which the solution is to use the template instance:

Template.myTemplate.onCreated(function(){
  Template.instance().variable = 1;
});

Template.myTemplate.helpers({
  variable: function() {
    return Template.instance().variable;
  }
});

A slight hacky-feeling approach is to pass a parameter you won’t use to the template:

{{> myTemplate _=""}}

That way the data context will be an object as opposed to the string it is when you use:

{{> myTemplate ""}}

That will make this work

Depending on your use case, you could also do:

{{> myTemplate variable=1}}

And of course, there’s my preferred option, using manuel:viewmodel:

Template.myTemplate.viewmodel({
  variable: 1
});

Note that is option is reactive, so it’s actually similar to doing

Template.myTemplate.onCreated(function(){
  Template.instance().variable = new ReactiveVar(1);
});

Template.myTemplate.helpers({
  variable: function() {
    return Template.instance().variable.get();
  }
});

A potential problem I see is if you use the template more than once at a time, both instances will be accessing the same variable, to which the solution is to use the template instance.

It’s okey for my use case, so using Template.myTemplate.x is my final option here. I want to thank you once again: this thread gave me a lot in understanding of how Meteor deals with data context. Passing _="" is an awesome trick.