Search code examples
meteormeteor-accounts

meteor how do I create form for users to update their profile details


As part of my app development env I have created some seed data that creates users and adds some data to their profile field.

I am now able to display that data in a profile view on my app.

My question is What would be the best way to allow users to add this data on registering?

I have tried a form to do this as part of a "profile" menu set but I was not successful in getting the data updated is the field. The new/updated data was not added.

My template looks like this

<template name="profileForm">
<form class="profileform form-horizontal" role="form">
    <div class="form-group">
        <!-- <label for="inputFirstName">First Name</label> -->
        <div class="col-sm-4">
            <input id="firstname" type="text" name="firstname" placeholder={{firstName}} />
        </div>
    </div>
    <div class="form-group">
        <!-- <label for="inputFirstName">Last Name</label> -->
        <div class="col-sm-4">
            <input id="lastname" type="text" name="lastname" placeholder={{lastName}} />
        </div>
    </div>
    <div class="form-group">
        <!-- <label for="inputFirstName">E-Mail Address</label> -->
        <div class="col-sm-4">
            <input id="email" type="email" name="email" placeholder={{email}} />
        </div>
    </div>
    <div class="form-group">
        <!-- <label for="inputFirstName">Phone Number</label> -->
        <div class="col-sm-4">
            <input id="phone" type="tel" name="phone" placeholder={{phoneNumber}} />
        </div>
    </div>
    <div class="form-group">
        <!-- <label for="inputFirstName">School</label> -->
        <div class="col-sm-4">
            <input id="school" type="text" name="school" placeholder={{schoolName}} />
        </div>
    </div>
    <div class="form-group">
        <!-- <label for="inputFirstName">First year</label> -->
        <div class="col-sm-4">
            <input id="firstschoolyear" type="text" name="firstschoolyear" placeholder={{firstSchoolYear}} />
        </div>
    </div>
    <div class="form-group">
        <!-- <label for="inputFirstName">Last Year</label> -->
        <div class="col-sm-4">
            <input id="lastschoolyear" type="text" name="lastschoolyear" placeholder={{lastSchoolYear}} />
        </div>
    </div>
    <div class="form-group">
        <div class="col-sm-4">
            <label>Did you Matriculate Here?</label>
        </div>
        <div class="col-xs-3">
            <select class="form-control">
                <option>Yes</option>
                <option>No</option>
            </select>
        </div>
    </div>
    <div class="form-group">
        <!-- <label for="inputFirstName">House Name</label> -->
        <div class="col-sm-4">
            <input id="housename" type="text" name="housename" placeholder={{houseName}} />
        </div>
    </div>
    <div class="form-group">
        <!-- <label for="inputFirstName">Country Living In</label> -->
        <div class="col-sm-4">
            <input id="country" type="text" name="country" placeholder={{country}} />
        </div>
    </div>
    <div class="form-group">
        <!-- <label for="inputFirstName">City</label> -->
        <div class="col-sm-4">
            <input id="cityofresidence" type="text" name="cityofresidence" placeholder={{cityOfResidence}} />
        </div>
    </div>
    <div class="form-group">
        <!-- <label for="inputFirstName">Employment Industry</label> -->
        <div class="col-sm-4">
            <input tid="emplindustry" ype="text" name="emplindustry" placeholder={{emplIndustry}} />
        </div>
    </div>
    <button class="profilesubmit">Update Profile</button>
</form>

My JS file looks like this

Template.profileForm.events({
  "submit .profileform": function (event) {
// This function is called when the profile form is submitted

var firstname = event.target.firstname.value,
 lastname = event.target.astname.value,
 email = event.target.email.value,
 phone = event.target.phone.value,
 school = event.target.school.value,
 firstschoolyear = event.target.firstschoolyear.value,
 lastschoolyear = event.target.lastschoolyear.value,
 matriculated = event.target.matriculated.value,
 housename = event.target.houseelname.value,
 country = event.target.country.value,
 cityofresidence = event.target.cityofresidence.value,
 emplindustry = event.target.emplindustry.value;

if(Meteor.userId())
 {
    Meteor.users.update({_id: Meteor.userId()},{$set:{
        "profile.firstname": firstname,      
        "profile.lastname": lastname,
        "profile.phone": phone,
        "profile.school": school,
        "profile.firstschoolyear": firstschoolyear,
        "profile.lastschoolyear": lastschoolyear,
        "profile.matriculated": matriculated,
        "profile.housename": housename,
        "profile.country": country,
        "profile.cityofresidence": cityofresidence,
        "profile.emplindustry": emplindustry,
        "profile.joined": new Date(), // current time
      }});
  }
// Clear form
//event.target.text.value = "";

// Prevent default form submit
return false;
  }
});

Template.profileForm.helpers({
  email: function() {return Meteor.user().emails[0].address},
  userName: function () {return Meteor.user().username},
  firstName: function () {return Meteor.user().profile.firstname},
  lastName: function () {return Meteor.user().profile.lastname},
  phoneNumber: function () {return Meteor.user().profile.phone},
  schoolName: function () {return Meteor.user().profile.schoolName},
  firstSchoolYear: function () {return Meteor.user().profile.firstschoolyear},
  lastSchoolYear: function () {return Meteor.user().profile.lastschoolyear},
  matriculated: function () {return Meteor.user().profile.matriculated},
  houseName: function () {return Meteor.user().profile.housename},
  country: function () {return Meteor.user().profile.country},
  cityOfResidence: function () {return Meteor.user().profile.cityofresidence},
  emplIndustry: function () {return Meteor.user().profile.emplindustry},
  signedUp: function () {return Meteor.user().profile.joined},
});

I have used the Allow function to allow users to edit their profiel field.

Meteor.publish("userData", function () {
  return Meteor.users.find({_id: this.userId},{ fields: {'profile': 1}});
});

Meteor.users.allow({
  update: function (userId, user, fields, modifier) {
    // can only change your own documents
    if(user._id === userId)
    {
      Meteor.users.update({_id: userId}, modifier);
      return true;
    }
    else return false;
  }
});

My subscription looks like this.

Meteor.subscribe('userData');

I strongly believe my lack of programming skill has lead me to leave something important out.


Solution

  • I would suggest to take a look at this three packages: aldeed:simple-schema, aldeed:autoform and aldeed:collection2. Their examples already contain answers to your questions!

    Simple-schema will allow you to quickly make, well, schemas for your documents (such as users), indicating the type of each field, the maximum length of arrays or Strings, and so on. Autoform allows you to quickly generate forms from this schema, while Collection2 allows you to bind a schema to a Collection and thus do the checks and cleaning automatically. In the end, if you have to change your document schema (for example by adding a new field), you will just have to change your schema and everything will change accordingly (> the way your form behaves depending on how you did it, the way your collection is managed).

    In your case,

    //Shared code
    var userProfileSchema = new SimpleSchema({
      firstName : {
        type : String,
        max : 100,
        defaultValue : ''
      },
      lastName : {
        type : String,
        max : 100,
        defaultValue : ''
      },
      email : {
        type : String,
        regEx : SimpleSchema.RegEx.Email,
        optional : true
      },
      ...
    });
    
    var userSchema = {
      //Add all the fields of a normal Meteor user
      //Then add your own schema:
      profile : userProfileSchema
    };
    
    Meteor.users.attachSchema(userSchema);
    

    Now your schema is properly defined and attached on the collection.
    The third part of the Triforce is now aldeed:autoform : Simply generate the form!

    {{> quickForm 
      schema=userProfileSchema doc=getProfile 
      type=method meteormethod="updateSelfProfile"
    }}