admin管理员组

文章数量:1313001

My client subscription routines are not refreshing when I update a collection:

server/publish.js

Meteor.publish('decisions', function (decisionCursor) {
    return Decisions.find({ active: true }, { limit: 20, skip: decisionCursor });
});

Meteor.publish('decisionsToModerate', function (decisionCursor) {
    return Decisions.find({ active: false }, { sort: { createdAt: -1 }, limit: 1, skip: decisionCursor });
});

I subscribe my client to both collection publications and when it fetchs all data it creates a session object with some stuff I need.

client/client.js

Meteor.startup(function () {
    SimpleSchema.debug = true;
    Deps.autorun(function () {
        Meteor.subscribe("decisions", Number(Session.get('decisionCursor')), function () {
            var decisionsVoted = {};
            Decisions.find({
                active: true
            }).forEach(function (decision) {
                var userVoted = Meteor.users.findOne({
                    "_id": Meteor.userId(),
                    "profile.votes.decision": decision._id
                }) != null ? Meteor.users.findOne({
                    "_id": Meteor.userId(),
                    "profile.votes.decision": decision._id
                }) : false;

                var ipVoted = Votes.findOne({
                    "ip": headers.get('x-forwarded-for'),
                    "votes.decision": decision._id
                }) != null ? true : false;
                if (ipVoted || userVoted)
                    decisionsVoted[decision._id] = {
                        voted: true,
                        blue: decision.blueTotal,
                        red: decision.redTotal,
                        bluePer: Math.round(decision.blueTotal * 100) / (decision.blueTotal + decision.redTotal),
                        redPer: Math.round(decision.redTotal * 100) / (decision.blueTotal + decision.redTotal)
                    };

            });
            Session.set('decisionsVoted', decisionsVoted);
        });
        Meteor.subscribe("decisionsToModerate", Number(Session.get('decisionCursor')));
    });
});

client/lib/environment.js

activeDecisions = function() {
    var decisions = Decisions.find({active: true});
    console.log(decisions.fetch().length);
    return decisions;
};
moderateDecisions = function() {
    return Decisions.find({active: false});
};

client/views/home/home.js

'click': function (event) {
    event.preventDefault();
    var decisionId = Session.get("selected_decision");
    var hasVoted = Session.get('decisionsVoted')[decisionId] ? Session.get('decisionsVoted')[decisionId].voted : false;

    Meteor.call("vote", decisionId, 'blue', hasVoted, function (error, result) {
        if (!error && result === true) {
            console.log(Session.get('decisionsVoted')[decisionId]); // UNDEFINED
        }
    });
},

When updating is successful, client subscriptioun should update creating a new object in my session object, right? Because collection is changed so publish in server is refreshed... But it does not refresh and what I mented // UNDEFINED instead of returning my new object is returning UNDEFINED

I don't know if that's the behaviour of Meteor or I'm missing something... I've tried to update parameter passed to publish method decisionCursor in order to force update but nothing hapens Session.set('decisionCursor', Session.get('decisionCursor'));

EDIT: it seems that if I use Session.set('decisionCursor', Session.get('decisionCursor') + 1); (note that +1) it is refreshed but not inside result function, if I click again it detects that new object is added... But I need it to be refreshed inside result function (inside my home.js click event)

My client subscription routines are not refreshing when I update a collection:

server/publish.js

Meteor.publish('decisions', function (decisionCursor) {
    return Decisions.find({ active: true }, { limit: 20, skip: decisionCursor });
});

Meteor.publish('decisionsToModerate', function (decisionCursor) {
    return Decisions.find({ active: false }, { sort: { createdAt: -1 }, limit: 1, skip: decisionCursor });
});

I subscribe my client to both collection publications and when it fetchs all data it creates a session object with some stuff I need.

client/client.js

Meteor.startup(function () {
    SimpleSchema.debug = true;
    Deps.autorun(function () {
        Meteor.subscribe("decisions", Number(Session.get('decisionCursor')), function () {
            var decisionsVoted = {};
            Decisions.find({
                active: true
            }).forEach(function (decision) {
                var userVoted = Meteor.users.findOne({
                    "_id": Meteor.userId(),
                    "profile.votes.decision": decision._id
                }) != null ? Meteor.users.findOne({
                    "_id": Meteor.userId(),
                    "profile.votes.decision": decision._id
                }) : false;

                var ipVoted = Votes.findOne({
                    "ip": headers.get('x-forwarded-for'),
                    "votes.decision": decision._id
                }) != null ? true : false;
                if (ipVoted || userVoted)
                    decisionsVoted[decision._id] = {
                        voted: true,
                        blue: decision.blueTotal,
                        red: decision.redTotal,
                        bluePer: Math.round(decision.blueTotal * 100) / (decision.blueTotal + decision.redTotal),
                        redPer: Math.round(decision.redTotal * 100) / (decision.blueTotal + decision.redTotal)
                    };

            });
            Session.set('decisionsVoted', decisionsVoted);
        });
        Meteor.subscribe("decisionsToModerate", Number(Session.get('decisionCursor')));
    });
});

client/lib/environment.js

activeDecisions = function() {
    var decisions = Decisions.find({active: true});
    console.log(decisions.fetch().length);
    return decisions;
};
moderateDecisions = function() {
    return Decisions.find({active: false});
};

client/views/home/home.js

'click': function (event) {
    event.preventDefault();
    var decisionId = Session.get("selected_decision");
    var hasVoted = Session.get('decisionsVoted')[decisionId] ? Session.get('decisionsVoted')[decisionId].voted : false;

    Meteor.call("vote", decisionId, 'blue', hasVoted, function (error, result) {
        if (!error && result === true) {
            console.log(Session.get('decisionsVoted')[decisionId]); // UNDEFINED
        }
    });
},

When updating is successful, client subscriptioun should update creating a new object in my session object, right? Because collection is changed so publish in server is refreshed... But it does not refresh and what I mented // UNDEFINED instead of returning my new object is returning UNDEFINED

I don't know if that's the behaviour of Meteor or I'm missing something... I've tried to update parameter passed to publish method decisionCursor in order to force update but nothing hapens Session.set('decisionCursor', Session.get('decisionCursor'));

EDIT: it seems that if I use Session.set('decisionCursor', Session.get('decisionCursor') + 1); (note that +1) it is refreshed but not inside result function, if I click again it detects that new object is added... But I need it to be refreshed inside result function (inside my home.js click event)

Share Improve this question edited May 21, 2014 at 2:54 Neil Lunn 151k36 gold badges355 silver badges325 bronze badges asked May 21, 2014 at 1:42 Robert W. HunterRobert W. Hunter 3,0037 gold badges36 silver badges74 bronze badges
Add a ment  | 

2 Answers 2

Reset to default 7

This (excellent) article might help. To paraphrase:

...on the server, Meteor’s reactivity is limited to cursors returned by Meteor.publish() functions. The direct consequence of this is that unlike on the client, code will not magically re-run whenever data changes.

The callback to Meteor.subscribe is called when the server marks the subscription as ready, and is not a reactive context, so it won't re-run when its dependencies change. (Reactive contexts aren't inherited like closure variables, the fact the callback is physically inside of the autorun is irrelevant.) You probably want a second autorun:

// original autorun
Deps.autorun(function() {
  var decSubscription = Meteor.subscribe("decisions", Number(Session.get('decisionCursor')));
  Meteor.subscribe("decisionsToModerate", Number(Session.get('decisionCursor')));

  // Store the subscription handle in a session variable so that
  // the new autorun re-runs if we resubscribe
  Session.set("decSubscription", decSubscription);
});

// new autorun
Deps.autorun(function() {
  // don't do anything if the subscription isn't ready yet
  var decCursor = Session.get("decSubscription");
  if (!decCursor.ready()) {
    Session.set("decisionsVoted", {});
    return;
  }
  var decisionsVoted = {};
  Decisions.find({active: true}).forEach(/* ... */);
  Session.set("decisionsVoted", decisionsVoted);
});

Note that we skip puting decisionsVoted if the subscription isn't ready, otherwise when the server is sending the initial result set, we will repute it after each individual document is sent.

本文标签: javascriptMeteor publish subscribe is not reactiveStack Overflow