Jason Ip
Jason Ip

Reputation: 353

Meteor method callback loop, what am I doing wrong?

I've been looking at this for awhile and I'm pretty sure it has something to do with an infinite callback loop.

I have a method that returns an integer from a collection called Sessions. Here are my methods:

Meteor.methods({

      going: function(sessionsId) {
        return Sessions.update(sessionsId, {$addToSet: {participants: Meteor.userId()}, $inc: {slots:-1}});  
      },

      retract: function(sessionsId) {
        return Sessions.update(sessionsId, {$pull: {participants: Meteor.userId()}, $inc: {slots:1}});  
      },

      sessionFull: function(sessionsId) {
        var session = Sessions.findOne({_id:sessionsId});
        console.log("gets here");
        return session.slots;
      }
    });

Then in my client I have:

if (Meteor.isClient) {
      Template.hello.sessions = function () {
        return Sessions.find();
      };

      Template.session.this_info = function () {
        return this._id;
      };  

      Template.session.isGoing = function() {
        var session = Sessions.find({_id:this._id, participants:Meteor.userId()}).count();
        if (session > 0) return true;
        else return false;
      };

      Template.session.sessionFull = function() {
        if (this.slots === 0) return true;
        else return false;
      };

      Template.session.slotsMethod = function () {
        Meteor.call('sessionFull',this._id, function(error, slots) {
          Session.set("slots",slots);
        });
        return Session.get("slots");
      };

      Template.session.events({
        'click input.going' : function () {
         //Sessions.update(this._id, {$inc: {slots: -1}}); 
         Meteor.call('going', this._id, function(error, updated) {
           if (error)
             return alert(error.reason);
         });
        },

        'click input.retract' : function () {
          Meteor.call('retract', this._id, function(error, removed) {
            if (error)
              return alert(error.reason);
          });
        }
      });

So I basically have a couple buttons that will increase or decrease the slots field and I want to have a method that will return what the slots field contains. Here is my template:

      {{#each sessions}}
        {{> session}}
      {{/each}}

    <template name="session">
    <br>
    {{date_time}}, {{duration}}
    {{#if isGoing}}
      <input type="button" class="retract" value="not going/give slot" />
    {{else}}
      {{#if sessionFull}}
        <h1>SORRY SESSION FULL</h1>
      {{else}} 
        <input type="button" class="going" value="going/subract slot" />
      {{/if}}
    {{/if}}
    {{participants}},{{sessionFull}},{{this_info}}
    </template>

If I try to add the Template.session.slotsMethod to my template (which calls the sessionFull Meteor method) I get an infinite loop, as in, it will display a rapidly changing integer for each session.

Am I doing something wrong?? Can't figure it out, I think it has something to with callbacks/async/sync but not sure.

Upvotes: 0

Views: 446

Answers (1)

go-oleg
go-oleg

Reputation: 19480

Yes, your Template.session.slotsMethod will cause an infinite loop since Session is reactive.

This is what happens:

  • Whenever Session.get("slots") changes, Template.session.slotsMethod will be called because its dependent on Session.get("slots").
  • However, Template.session.slotsMethod itself is also updating the value of Session.get("slots") so the process starts all over again.

Not quite sure when you want Template.session.slotsMethod to be run, but you probably want to break it up into two pieces, something like:

Template.session.getSlots = function () {
  return Session.get("slots");
};

and

Meteor.call('sessionFull',this._id, function(error, slots) {
  Session.set("slots",slots);
});

needs to go wherever/whenever you need to do the sessionFull check, perhaps in Template.session.rendered?

Upvotes: 1

Related Questions