3

So what I am trying to do is make an HTTP get request and then update a view with the response. For some reason it's not working. Here is what I have.

I have been following this gist: https://gist.github.com/3443021

On the client:

Template.search.items = function() {
    var query = Session.get("query");
    console.log(query);
    var resp;
    Meteor.call("search", query, function(err, res) {
        console.log(res);
        //return res;
        return [1,2,4];
    });
};

On the server:

Meteor.methods({
    search: function(query) {
        var fut = new Future();
        // var onComplete = fut.resolver();

        Meteor.http.get("http://localhost:4242/autocomplete/"+query, function(err, res) {
            var content = res.content;
            var resp = JSON.parse(content);
            console.log(resp);
            fut.ret(resp)
        });
        return fut.wait();
    }
});

And on the view I am doing:

<template name="search">
<h1>test</h1>
<table class="table table-hover">
<tbody>
  {{#each items}}
    {{> searchItem}}
  {{/each}}
</tbody>

It seems if I return from inside the Meteor.call function nothing gets sent to the view. Any ideas?

bramp
  • 9,581
  • 5
  • 40
  • 46
Jonovono
  • 3,437
  • 5
  • 42
  • 64

2 Answers2

2

In the client, there are no fibers or anything, Meteor.call is asynchronous and the template will get no return value from the helper.

From the documentation:

On the client, if you do not pass a callback and you are not inside a stub, call will return undefined, and you will have no way to get the return value of the method. That is because the client doesn't have fibers, so there is not actually any way it can block on the remote execution of a method.

You could use the rendered callback to manipulate the template manually after it was changed.

Template.search.rendered = function() {
  var query = Session.get("query"),
      table = this.find('.table-container');
  console.log(query);
  var resp;
  Meteor.call("search", query, function(err, res) {
    console.log(res);
    table.innerHTML = Template.search_items(res); // render the table with another template
  });
}
Andreas
  • 1,622
  • 14
  • 13
1

I'm using this solution, more complicated, but without session. But better way is to use some model on the background (template can be called with model - with {{#with}} handlebar). I 'll only show this principle...

Template.search.items= function() {

 //todo: move this 'Promiss' class to shared code.
 var Promiss = function (iniValue) {

    var self = this;

    //-- Reactive Property Result, setter & getter
    this._result = iniValue;
    this._resultDeps = new Deps.Dependency;
    this.setResult = function(value) {

        self._result = value;
        self._resultDeps.changed();
        //at this moment template will be recomputed, because we have
        // changed '_resultDeps'
    };

    this.getResult = function() {
        Deps.depend(self._resultDeps);
        return self._result;
    };

  }; //end of Promiss class


//after recompution we take saved result
if (this._backupSearchPromiss)
    return this._backupSearchPromiss;

var promiss = new Promiss([/*ini value untill server response*/]);
this._backupSearchPromiss= promiss;

//call server..
Meteor.call("search", function (err, result) {
    //todo: handle error
    promiss.setResult(result);

});
return promiss;

};//end of template method

And in html:

{{#each search.getResult}}
  {{>searchItem}}
{{/each}}
user2958194
  • 116
  • 2
  • 3