简体   繁体   中英

Meteor update user profile

I have no idea what's going wrong in my app. I'm trying to update a user profile. If a user has already a profile, it should display the current values of the profile. I have a SimpleSchema attached to the user collection.

<template name="updateCustomerProfile">
  <div class="container">
    <h1>Edit User</h1>
    {{#if isReady 'updateCustomerProfile'}}
      {{#autoForm collection="Users" doc=getUsers id="profileForm" type="update"}}
        <fieldset>
          {{> afQuickField name='username'}}
          {{> afObjectField name='profile'}}
        </fieldset>
        <button type="submit" class="btn btn-primary">Update User</button>
        <a class="btn btn-link" role="button" href="{{pathFor 'adminDocuments'}}">Back</a>
      {{/autoForm}}
    {{else}}
      Nothing
    {{/if}}
   </div>
</template>

I have a template helper:

Template.updateCustomerProfile.events({
getUsers: function () {
    //return Users.findOne();
    return Meteor.user();
  }
});

I have an Autoform hook

AutoForm.addHooks(['profileForm'], { 
    before: {
      insert: function(error, result) {
        if (error) {
          console.log("Insert Error:", error);
          AutoForm.debug();
        } else {
          console.log("Insert Result:", result);
          AutoForm.debug();
        }
      },
      update: function(error) {
        if (error) {
          console.log("Update Error:", error);
          AutoForm.debug();
        } else {
          console.log("Updated!");
          console.log('AutoForm.debug()');
        }
      }
    }
  });

Have the following route:

customerRoutes.route('/profile/edit', {
  name: "updateCustomerProfile",
  subscriptions: function (params, queryParams) {
    this.register('updateCustomerProfile', Meteor.subscribe('usersAllforCustomer',  Meteor.userId()));
  },
  action: function(params, queryParams) {
    BlazeLayout.render('layout_frontend', {
      top: 'menu',
      main: 'updateCustomerProfile',
      footer: 'footer'
    });
  }
});

and finally the following publication:

Meteor.publish('usersAllforCustomer', function (userId) {
    check(userId, String);
    var user = Users.findOne({_id: userId});
    if (Roles.userIsInRole(this.userId, 'customer')) {
        return Users.find({_id: userId});
    }
});

And here is the collection:

Users = Meteor.users;

Schema = {};

Schema.UserProfile = new SimpleSchema({
    firstName: {
        type: String,
        optional: true
    },
    lastName: {
        type: String,
        optional: true
    },
    gender: {
        type: String,
        allowedValues: ['Male', 'Female'],
        optional: true
    },
    organization : {
        type: String,
        optional: true
    }
});

Schema.User = new SimpleSchema({
    username: {
        type: String,
        optional: true
    },
    emails: {
        type: Array,
        optional: true
    },
    "emails.$": {
        type: Object
    },
    "emails.$.address": {
        type: String,
        regEx: SimpleSchema.RegEx.Email
    },
    "emails.$.verified": {
        type: Boolean
    },
    createdAt: {
        type: Date,
        optional: true,
        denyUpdate: true,
        autoValue: function() {
            if (this.isInsert) {
                return new Date();
            }
        }
    },
    profile: {
        type: Schema.UserProfile,
        optional: true
    },
    services: {
        type: Object,
        optional: true,
        blackbox: true
    },
    roles: {
        type: [String],
        optional: true
    }
});

Meteor.users.attachSchema(Schema.User);

I'm sure the user object is passed in the publication. I can't update the profile: getting the following error (from Autoform debug):

Update Error: Object {$set: Object}
   $set: Object
        profile.firstName: "test_firstname"
        profile.gender: "Female"
        profile.lastName: "test_lastname"
        profile.organization: "test_organisation
        "username: "test_username"

How to go about updating a profile, staring blind....

You need to change your before AutoForm Hooks .

AutoForm.addHooks(['profileForm'], {
  before: {
    insert: function(doc) {
      console.log('doc: ', doc);
      return doc;
    },

    update: function(doc) {
      console.log('doc: ', doc);
      return doc;
    },
  },
});

While the after callback has the js standard (error, result) function signature, the before callback has just one parameter, the doc to insert/update. This is why you are always logging an 'error', it is just the doc you want to insert. Also you need to either return it, or pass it to this.result to actually insert/update the object in the db.

From the docs:

var hooksObject = {
  before: {
    // Replace `formType` with the form `type` attribute to which this hook applies
    formType: function(doc) {
      // Potentially alter the doc
      doc.foo = 'bar';

      // Then return it or pass it to this.result()
      return doc; (synchronous)
      //return false; (synchronous, cancel)
      //this.result(doc); (asynchronous)
      //this.result(false); (asynchronous, cancel)
    }
  },

There are a couple small issues so I'm not sure how to tackle your problem, but here's some things to address.

Publish Method

  • Local variable user is never used. Were you trying to use it?
  • No need to include userId as a function parameter since you have access to this.userId
  • The current user's profile is published by default so you don't need to use publish/subscribe unless you want to include/exclude fields, but then I would define a Meteor.publish(null, ...) so that it overrides the default current user publication

Note: If you remove publish usersAllforCustomer function, don't forget to remove it from route updateCustomerProfile

Use Global Helper currentUser

Here's how to update your template to use currentUser instead of getUsers

<template name="updateCustomerProfile">
  <div class="container">
    <h1>Edit User</h1>
    {{#with currentUser}}
      {{#autoForm collection="Users" doc=this id="profileForm" type="update"}}
        <fieldset>
          {{> afQuickField name='username'}}
          {{> afObjectField name='profile'}}
        </fieldset>
        <button type="submit" class="btn btn-primary">Update User</button>
        <a class="btn btn-link" role="button" href="{{pathFor 'adminDocuments'}}">Back</a>
      {{/autoForm}}
    {{else}}
      Nothing
    {{/with}}
   </div>
</template>

Hope this helps.

The meteorpad indeed solved the issue. There was a mistake in the helper. In fact, the original code was:

Template.updateCustomerProfile.events({
getUsers: function () {
    return Meteor.user();
  }
});

So in above snippet I was using an 'events' instead of an 'helper'. Below is the correct code:

Template.updateCustomerProfile.helpers({
  getUsers: function(){
    return Meteor.user();
  }
});

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