JD.
JD.

Reputation: 2487

How to update user field in angular-meteor?

I've configured all users to be created with an empty favorites array: user.favorites: []

Since the users collection is treated differently, how should I publish, subscribe, and access subscribed favorites data in angular-meteor?

Here's what I have so far:

// Meteor.methods ==========================================
addFavorite: function(attendeeId){

var loggedInUser = Meteor.user();
if( !loggedInUser ){
  throw new Meteor.Error("must be logged in");
}

    loggedInUser.favorites.push(attendeeId);
    loggedInUser.username = loggedInUser.username+"x";

    console.log(loggedInUser.favorites);

}


// controller ========================================
    $scope.addFavorite = function(attendeeId){
        $meteor.call("addFavorite", attendeeId);
    }

// server =======================================================
Meteor.publish('myFavorites', function(){
    if(!this.userId) return null;

    return Meteor.users.find(this.userId);
});

Meteor.users.allow({

    insert: function(userId, doc){
        return true;
    },

    update: function(useId, doc, fieldNames, modifier){
        return true;
    },

    remove: function(userId, doc){
        return true;
    }

});

User.favorites is empty. When addFavorite is called, it logs an array with a single userId that doesn't update the mongoDB at all. It looks as if Meteor.user() isn't reactivly updating. Does anyone know what I'm doing wrong? Thank you!

EDIT Latest iteration of code. Favorites are passed into $scope.favorites but isn't reactive. How do I fix this? Thanks!

// publish
Meteor.publish('myFavorites', function(){
    if(this.userId){
        return Meteor.users.find(this.userId, {
            fields: {
                favorites: 1
            }
        });
    }else{
        this.ready();
    }
});

// subscribe
$meteor.subscribe('myFavorites')
    .then(function(subscriptionHandle)
{
    var user = $meteor.collection(function(){
        return Meteor.users.find({_id: Meteor.userId()});
    });
    $scope.favorites = user[0].favorites;
});

Upvotes: 2

Views: 816

Answers (1)

JacobWuzHere
JacobWuzHere

Reputation: 913

tldr;

Accounts collection is reactive, but by default only the username, emails, and profile fields are published. The quickest fix is to attach the favorites as a new field on the User.profile object.

// Meteor.methods ==========================================
addFavorite: function(attendeeId){

var loggedInUser = Meteor.user();
if( !loggedInUser ){
  throw new Meteor.Error("must be logged in");
}
    if (loggedInUser.profile.favorites){
        loggedInUser.profile.favorites.push(attendeeId);
    }
    else {
        loggedInUser.profile.favorites = [];
        loggedInUser.profile.favorites.push(attendeeId);
    }
    loggedInUser.username = loggedInUser.username+"x";

    console.log(loggedInUser.profile.favorites);

}

Although right now you probably are writing to the user, which you can verify by using meteor mongo --> db.users.find().pretty(), but the subscription does not publish your favorites field.

Alternative approach

Alternatively, you can publish the favorites field

// Server code --------
Meteor.publish("userData", function () {
  if (this.userId) {
    return Meteor.users.find({_id: this.userId},
                             {fields: {'favorites': 1}});
  } else {
    this.ready();
  }
});

Opinionated Meteor.users philosophy

I like to structure my users object around 3 properties:

  • User.profile --> published to the client, and directly modifiable by the client through client-side code
  • User.public --> published to the client, but not modifiable except through server-side Meteor methods
  • User.private --> not published to the client (i.e. only accessible to read on server code), and only modifiable by server code (with client simulation)

Just make sure that when you remove the insecure and autopublish packages that you double-check your Collections security by using the Meteor.users.allow() function in your server code

Run meteor list to if you want to verify whether or not insecure and autopublish packages are being used in your current project. NOTE: By default Meteor does install them when you first create your app)

// Server code --------
Meteor.publish("userData", function () {
  if (this.userId) {
    return Meteor.users.find({_id: this.userId},
                             {fields: {'public': 1}});
  } else {
    this.ready();
  }
});

Upvotes: 2

Related Questions