Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Meteor.js: how to call helper method from event?

I suspect I'm not doing this the Meteor way. I'm making a shared, interactive calendar.

I have a calendar template:

<template name="calendar">
<h2>Calendar</h2>
<div class="calendar">{{#each days}}
    {{> day}}
    {{/each}}
</div>
</template>

With a helper that returns a day object:

     {
        date: thisDate.getDate(),
        dateString: dateString,
        done: done,
        today: isToday
      }

I have a day template:

<template name="day">
  <div class="day {{stateString}}">{{date}}</div>
</template>

With some helpers (meetingID is hardcoded for now for development):

  Template.day.helpers({
    state: function(){
      // retreive from DB
      var s = Meetings.findOne({"_id":meetingID}).dates[this.dateString];
      return s;
    }
    stateString: function(){
      var stateString;

      switch(this.state){
        case -1: stateString = "unknown"; break;
        case 0: stateString = "unavailable"; break;
        case 1: stateString = "available"; break;
      }
      if(this.done) stateString = "done";

      return stateString;
    }
  });

state() gets the state from the db and stateString() picks the right class name for that state.

When you click on it, you cycle through states (1: available, 0: not available, -1: unknown):

  Template.day.events({
    "click": function(){
      if(this.done) return false;   // no state changes for past days!
      console.log(e);
      var newState = this.state + 1;
      if(newState > 1) newState = -1;

      var q = "dates."+this.dateString+"."+Meteor.userId()+".state";
      console.log(q+ " / "+this.state+" / "+newState);
      Meetings.update(meetingID, {$set:{q:newState}});

      return false;
    }
  })

I'm having at least two specific problems:

1) How do I call the state() helper from the click event? 2) My db update doesn't seem to work—it's creating a 'q' document instead of using the string stored in q.

I'm sure this is missing some fundamental understanding of the right way to do this—please help!

like image 526
T3db0t Avatar asked Dec 04 '14 21:12

T3db0t


People also ask

How do I call a method from the client in Meteor?

This Method is callable from the client and server using Meteor.call. Note that you should only use a Method in the case where some code needs to be callable from the client; if you just want to modularize code that is only going to be called from the server, use a regular JavaScript function, not a Method.

What is Meteor API?

Meteor API Docs. What is Meteor? Meteor is a full-stack JavaScript platform for developing modern web and mobile applications. Meteor includes a key set of technologies for building connected-client reactive applications, a build tool, and a curated set of packages from the Node.js and general JavaScript community.

How do you handle errors in Meteor methods?

Error handling. In regular JavaScript functions, you indicate errors by throwing an Error object. Throwing errors from Meteor Methods works almost the same way, but a bit of complexity is introduced by the fact that in some cases the error object will be sent over a websocket back to the client.

What are methods in Meteor?

Methods are Meteor’s remote procedure call (RPC) system, used to save user input events and data that come from the client. If you’re familiar with REST APIs or HTTP, you can think of them like POST requests to your server, but with many nice features optimized for building a modern web application.


3 Answers

Just expanding on the answer by @mark. You probably want to store state as a reactive variable so that your stateString helper will update when the state changes. If I understand correctly, you are not actually trying to use the state helper in your template - it is just needed for the string helper and the event. First add the reactive-var package:

meteor add reactive-var

I would recommend doing something like this for your template:

Template.day.created = function() {
  this.state = new ReactiveVar();
  this.autorun(_.bind(function() {
    var meetingDates = Meetings.findOne(meetingID).dates[this.data.dateString];
    var currentState = meetingDates[Meteor.userId()].state;
    this.state.set(currentState);
  }, this);
};

Template.day.helpers({
  stateString: function() {
    if (this.done) {
      return 'done';
    }
    switch(Template.instance().state.get()) {
      case -1: return 'unknown';
      case 0: return 'unavailable';
      case 1: return 'available';
    }
  }
});

Template.day.events({
  'click': function(event, template) {
    if (this.done) {
      return;
    }

    var newState = template.state.get() + 1;
    if (newState > 1) {
      newState = -1;
    }

    var modifier = {$set: {}}
    modifier.$set['dates.'+this.dateString+'.'+Meteor.userId()+'.state'] = newState;

    Meetings.update(meetingID, modifier);
  }
});
like image 65
sbking Avatar answered Oct 02 '22 13:10

sbking


Access template helpers from anywhere:

Template.<name>.__helpers.get('<helper>').call()
like image 24
Adam Moisa Avatar answered Oct 02 '22 13:10

Adam Moisa


Off the top of my head, one way to persist data between helpers and events in the same template is to store it as a property inside the template instance. So for example, you might have something that looks like this:

Template.day.created = function () {
  // here `this` refers to template instance
  this.state = -1;
};

Template.day.helpers({
  state: function () {
    var s = Meetings.findOne({"_id":meetingID}).dates[this.dateString];
    Template.instance().state = s;
    return s;
  },
  ...
});

Template.day.events({
  'click': function () {
    ...
    var state = Template.instance().state;
    ...
  }
});

As for the issue with q, you have to construct the object prior, otherwise q will be interpreted as the actual field name rather than a variable (notice how there's no distinction between "q" and q inside the query).

var query = {};
query[q] = newState;
Meetings.update(meetingID, { $set: query });

Hope this helps!

like image 40
mark Avatar answered Oct 02 '22 14:10

mark