最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How do you conditionally send data to the client in Meteor? - Stack Overflow

programmeradmin5浏览0评论

I'm trying to figure out how to conditionally send data to the client in meteor. I have two user types, and depending on the type of user, their interfaces on the client (and thus the data they require is different).

Lets say users are of type counselor or student. Every user document has something like role: 'counselor' or role: 'student'.

Students have student specific information like sessionsRemaining and counselor, and counselors have things like pricePerSession, etc.

How would I make sure that Meteor.user() on the client side has the information I need, and none extra? If I'm logged in as a student, Meteor.user() should include sessionsRemaining and counselor, but not if I'm logged in as a counselor. I think what I may be searching for is conditional publications and subscriptions in meteor terms.

I'm trying to figure out how to conditionally send data to the client in meteor. I have two user types, and depending on the type of user, their interfaces on the client (and thus the data they require is different).

Lets say users are of type counselor or student. Every user document has something like role: 'counselor' or role: 'student'.

Students have student specific information like sessionsRemaining and counselor, and counselors have things like pricePerSession, etc.

How would I make sure that Meteor.user() on the client side has the information I need, and none extra? If I'm logged in as a student, Meteor.user() should include sessionsRemaining and counselor, but not if I'm logged in as a counselor. I think what I may be searching for is conditional publications and subscriptions in meteor terms.

Share Improve this question asked Dec 28, 2012 at 19:05 DiogenesDiogenes 2,7573 gold badges26 silver badges27 bronze badges 2
  • I've gotten a few answers now and I'm not sure I know how to pick the best because they all seem to work on the surface. I guess I'd like the simplest, most 'meteoric' version which works for even more plex situations (i.e. when roles are not mutually exclusive, etc.) – Diogenes Commented Dec 28, 2012 at 23:00
  • In that case you should probably pick @debergalis's answer since he's one of the creators of Meteor. Doesn't get much more meteoric than that :) – Rahul Commented Dec 28, 2012 at 23:08
Add a ment  | 

3 Answers 3

Reset to default 13

Use the fields option to only return the fields you want from a Mongo query.

Meteor.publish("extraUserData", function () {
  var user = Meteor.users.findOne(this.userId);
  var fields;

  if (user && user.role === 'counselor')
    fields = {pricePerSession: 1};
  else if (user && user.role === 'student')
    fields = {counselor: 1, sessionsRemaining: 1};

  // even though we want one object, use `find` to return a *cursor*
  return Meteor.users.find({_id: this.userId}, {fields: fields});
});

And then on the client just call

Meteor.subscribe('extraUserData');

Subscriptions can overlap in Meteor. So what's neat about this approach is that the publish function that ships extra fields to the client works alongside Meteor's behind-the-scenes publish function that sends basic fields, like the user's email address and profile. On the client, the document in the Meteor.users collection will be the union of the two sets of fields.

Meteor users by default are only published with their basic information, so you'll have to add these fields manually to the client by using Meteor.publish. Thankfully, the Meteor docs on publish have an example that shows you how to do this:

// server: publish the rooms collection, minus secret info.
Meteor.publish("rooms", function () {
  return Rooms.find({}, {fields: {secretInfo: 0}});
});

// ... and publish secret info for rooms where the logged-in user
// is an admin. If the client subscribes to both streams, the records
// are merged together into the same documents in the Rooms collection.
Meteor.publish("adminSecretInfo", function () {
  return Rooms.find({admin: this.userId}, {fields: {secretInfo: 1}});
});

Basically you want to publish a channel that returns certain information to the client when a condition is met, and other info when it isn't. Then you subscribe to that channel on the client.

In your case, you probably want something like this in the server:

Meteor.publish("studentInfo", function() {
  var user = Meteor.users.findOne(this.userId);

  if (user && user.type === "student")
    return Users.find({_id: this.userId}, {fields: {sessionsRemaining: 1, counselor: 1}});
  else if (user && user.type === "counselor")
    return Users.find({_id: this.userId}, {fields: {pricePerSession: 1}});
});

and then subscribe on the client:

Meteor.subscribe("studentInfo");

Because Meteor.users is a collection like any other Meteor collection, you can actually refine its publicized content like any other Meteor collection:

Meteor.publish("users", function () {
    //this.userId is available to reference the logged in user 
    //inside publish functions
    var _role = Meteor.users.findOne({_id: this.userId}).role;
    switch(_role) {
        case "counselor":
            return Meteor.users.find({}, {fields: { sessionRemaining: 0, counselor: 0 }});
        default: //student
            return Meteor.users.find({}, {fields: { counselorSpecific: 0 }});
    }
});

Then, in your client:

Meteor.subscribe("users");

Consequently, Meteor.user() will automatically be truncated accordingly based on the role of the logged-in user.

Here is a plete solution:

if (Meteor.isServer) {
    Meteor.publish("users", function () {
        //this.userId is available to reference the logged in user 
        //inside publish functions
        var _role = Meteor.users.findOne({ _id: this.userId }).role;
        console.log("userid: " + this.userId);
        console.log("getting role: " + _role);
        switch (_role) {
            case "counselor":
                return Meteor.users.find({}, { fields: { sessionRemaining: 0, counselor: 0 } });
            default: //student
                return Meteor.users.find({}, { fields: { counselorSpecific: 0 } });
        }
    });

    Accounts.onCreateUser(function (options, user) {
        //assign the base role
        user.role = 'counselor' //change to 'student' for student data

        //student specific
        user.sessionRemaining = 100;
        user.counselor = 'Sam Brown';

        //counselor specific
        user.counselorSpecific = { studentsServed: 100 };

        return user;
    });
}

if (Meteor.isClient) {
    Meteor.subscribe("users");

    Template.userDetails.userDump = function () {
        if (Meteor.user()) {
            var _val = "USER ROLE IS " + Meteor.user().role + " | counselorSpecific: " + JSON.stringify(Meteor.user().counselorSpecific) + " | sessionRemaining: " + Meteor.user().sessionRemaining + " | counselor: " + Meteor.user().counselor;
            return _val;
        } else {
            return "NOT LOGGED IN";
        }
    };
}

And the HTML:

<body>
    <div style="padding:10px;">
        {{loginButtons}}
    </div>

    {{> home}}
</body>

<template name="home">
    <h1>User Details</h1>
    {{> userDetails}}
</template>

<template name="userDetails">
   DUMP:
   {{userDump}}
</template>
发布评论

评论列表(0)

  1. 暂无评论