meteor - with - spacebars blaze




Meteor: Access Template Helper(or variable) from another helper (6)

Disclaimer: This may not answer your question directly, but it might be helpful for people stuck with a similar use case:

Sometimes it's easy to get locked into the "Meteor way", that standard Javascript rules are forgotten.

Two use cases that sound similar to what you're trying to do:

1. For helpers/events that you can access anywhere on the client-side, simply set a global helper.

Put this in, say, client/helpers.js:

Helpers = {
    someFunction: function(params) {
        /* Do something here */
    }
}

Now Helpers.someFunction() is available to all templates.

If you want to bind the local template instance to it for some reason, again, it's standard JS:

var boundFunction = Helpers.someFunction.bind(this);

2. To create reusable Blaze helpers inside of templates, use Template.registerHelper

For example, this function uses the "numeral" library to format numbers:

Template.registerHelper('numeral', function(context, opt) {
    var format = (opt.hash && opt.hash.format) || '0,0.00';
    return numeral(context || 0).format(format);
});

You can use this in any template like so:

{{numeral someNumberVariable format='0,0'}}

How can I reference a template helper from another one? For example...

Template.XXX.helpers({
    reusableHelper: function() {
        return this.field1 * 25 / 100; //or some other result
    },
    anotherHelper: function() {
        if (this.reusableHelper() > 300) //this does not work
            return this.reusableHelper() + ' is greater than 300'; 
        else
            return this.reusableHelper() + ' is smaller than 300';
    }
});

I have also tried Template.instance().__helpers.reusableHelper - all with no luck.

Alternatively is there a way to define reactive Template instance variables?

XXX is a sub-template that renders multiple times on the same page.


Adding on to Nils' answer, I have been able to access Template level helpers in events using the following code:

'click a#back': (event, instance) ->
    if instance.view.template.__helpers[' complete']() && instance.view.template.__helpers[' changed']()
        event.preventDefault()

Since this answer is currently missing - I wanted to add an update

In the current meteor version, you should be able to call:

var TEMPLATE_NAME = //the name of your template...
var HELPER_NAME = //the name of your helper...
Template[TEMPLATE_NAME].__helpers[' '+HELPER_NAME]

You should call it like this, if you want to make sure the helper has access to this:

var context = this;
Template[TEMPLATE_NAME].__helpers[' '+HELPER_NAME].call(context,/* args */);

But be careful - this could break in future Meteor versions.


This like using of common code, you can make another javascript function which contains the your reusable code and call it from wherever you required.

Like in your code-

function calcField(field){
   return field * 25 / 100
}

and in you template helper-

Template.XXX.helpers({
    reusableHelper: function() {
        return calcField(this.field1); 
    },
    anotherHelper: function() {
        if (calcField(this.field1) > 300) 
            return calcField(this.field1) + ' is greater than 300'; 
        else
            return calcField(this.field1) + ' is smaller than 300';
    }
});

and

Alternatively is there a way to define reactive Template instance variables?

you can use Session variables or Reactive variable


i had something similar -- i had 2 helpers in the same template that needed access to the same function. however, that function 1) needed access to a reactive var in the template, and 2) is a filter function, so i couldn't just pass in the data of that reactive var.

i ended up defining the filter function in the templates onCreated() and stored it in a reactive var, so the helpers could access it.

Template.Foo.onCreated(function () {

    this.fooData = new ReactiveVar();

    function filterFoo(key) {
        var foo = Template.instance().fooData.get();
        // filter result is based on the key and the foo data
        return [true|false];
    }

    this.filterFoo = new ReactiveVar(filterFoo);

});

Template.Foo.helpers({
    helper1: function() {
        var filterFn = Template.instance().filterFoo.get();
        return CollectionA.getKeys().filter(filterFn);
    },
    helper2: function() {
        var filterFn = Template.instance().filterFoo.get();
        return CollectionB.getKeys().filter(filterFn);
    },

});

this just came up again at work, and this time we used modules. in this case, we had a number of large, related functions that had to maintain data across calls. i wanted them outside the template file but not totally polluting the Meteor scope. so we made a module (polluting the Meteor scope 1x) and called the functions therein from the template.

lib/FooHelpers.js:

FooHelpers = (function () {
    var _foo;

    function setupFoo(value) {
        _foo = value;
    }

    function getFoo() {
        return _foo;
    }

    function incFoo() {
        _foo++;
    }

    return {
        setupFoo: setupFoo,
        getFoo: getFoo,
        incFoo: incFoo
    }
})();

FooTemplate.js:

Template.FooTemplate.helpers({
    testFoo: function() {
        FooHelpers.setupFoo(7);
        console.log(FooHelpers.getFoo());
        FooHelpers.incFoo();
        console.log(FooHelpers.getFoo());
    }
});

console output is 7, 8.





meteor-helper