简体   繁体   中英

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!

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);
  }
});

从任何地方访问模板助手:

Template.<name>.__helpers.get('<helper>').call()

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!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM