Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use Meteor methods inside of a template helper

How can I define a Meteor method which is also callable in a template helper?

I have these two files:

file: lib/test.js

Meteor.methods({
    viewTest : function (str) {
        return str;
    }
});

file: client/myView.js

Template.helloWorld.helpers({
    txt : function () {
        var str = Meteor.call('viewTest', 'Hello World.');
        return str;
    }
});

When I give "str" a normal string everything works fine. But in this case my template does not get any value. I defined - for the test - in the same file where the method is a normal function and tried to call the function. The error I got was that the function does not exist. So I think that Meteor tries to render the template before it knows anything about the methods I defined for it. But I think that this is a bit unusual - isn't it?

like image 344
TJR Avatar asked Mar 03 '14 13:03

TJR


3 Answers

There is now a new way to do this (Meteor 0.9.3.1) which doesn't pollute the Session namespace

Template.helloWorld.helpers({
    txt: function () {
        return Template.instance().myAsyncValue.get();
    }
});

Template.helloWorld.created = function (){
    var self = this;
    self.myAsyncValue = new ReactiveVar("Waiting for response from server...");
    Meteor.call('getAsyncValue', function (err, asyncValue) {
        if (err)
            console.log(err);
        else 
            self.myAsyncValue.set(asyncValue);
    });
}

In the 'created' callback, you create a new instance of a ReactiveVariable (see docs) and attach it to the template instance.

You then call your method and when the callback fires, you attach the returned value to the reactive variable.

You can then set up your helper to return the value of the reactive variable (which is attached to the template instance now), and it will rerun when the method returns.

But note you'll have to add the reactive-var package for it to work

$ meteor add reactive-var
like image 120
Petrov Avatar answered Oct 05 '22 08:10

Petrov


Sashko added a neat little package called meteor-reactive-method to solve this problem.

$ meteor add simple:reactive-method
Template.helloWorld.helpers({
  txt: function() {
    return ReactiveMethod.call('viewTest', 'Hello World.');
  }
});

As I point out in common mistakes, helpers should be side-effect free, so I'd use this technique with caution. However, it's a really handy shortcut for cases where:

  • The helper should fire only once (it doesn't depend on reactive state).
  • The invoked method doesn't mutate the database.
like image 36
David Weldon Avatar answered Oct 05 '22 06:10

David Weldon


You need to interface your return value with a Session variable as the request is asynchronous:

Template.helloWorld.helpers({
    txt : function () {
        return Session.get("txt") || "Loading";
    }
});

Template.helloWorld.created = function() {
    Meteor.call('viewTest', 'Hello World.', function(err, result) {
        Session.set("txt", result);
    });

}

So .rendered should be called once when your template loads (at least it should with the newer version of Meteor.)

The value would be called and displayed. Otherwise it would say "Loading".

like image 12
Tarang Avatar answered Oct 05 '22 07:10

Tarang