I am trying to build a contact form which is very similar to the one used in the keystone demo but i have hit a road block, While trying to save to db, I get the following errors
{ message: 'Validation failed',
name: 'ValidationError',
errors:
{ name:
{ name: 'ValidatorError',
path: 'name',
message: 'Name is required',
type: 'required' } } }
I have checked the fields on the form and also the request in the backend by doing a console.log but for some reason i still keep on getting the same error.
Here is what I have in my jade file
section#contact-container
section#contact.contact-us
.container
.section-header
// SECTION TITLE
h2.white-text Get in touch
// SHORT DESCRIPTION ABOUT THE SECTION
h6.white-text
| Have any question? Drop us a message. We will get back to you in 24 hours.
if enquirySubmitted
.row
h3.white-text.wow.fadeInLeft.animated(data-wow-offset='30', data-wow-duration='1.5s', data-wow-delay='0.15s') Thanks for getting in touch.
else
.row
form#contact.contact-form(method="post")
input(type='hidden', name='action', value='contact')
.wow.fadeInLeft.animated(data-wow-offset='30', data-wow-duration='1.5s', data-wow-delay='0.15s')
.col-lg-4.col-sm-4(class=validationErrors.name ? 'has-error' : null)
input.form-control.input-box(type='text', name='name', value=formData.name, placeholder='Your Name')
.col-lg-4.col-sm-4
input.form-control.input-box(type='email', name='email', value=formData.email, placeholder='Your Email')
.col-lg-4.col-sm-4
div(class=validationErrors.enquiryType ? 'has-error' : null)
input.form-control.input-box(type='text', name='enquiryType', placeholder='Subject', value=formData.enquiryType)
.col-md-12(class=validationErrors.message ? 'has-error' : null)
.col-md-12.wow.fadeInRight.animated(data-wow-offset='30', data-wow-duration='1.5s', data-wow-delay='0.15s')
textarea.form-control.textarea-box(name='message', placeholder='Your Message')= formData.message
button.btn.btn-primary.custom-button.red-btn.wow.fadeInLeft.animated(data-wow-offset='30', data-wow-duration='1.5s', data-wow-delay='0.15s', type='submit') Send Message
and this is how my schema and route file looks like
var keystone = require('keystone'),
Types = keystone.Field.Types;
var Enquiry = new keystone.List('Enquiry', {
nocreate: true,
noedit: true
});
Enquiry.add({
name: { type: Types.Name, required: true },
email: { type: Types.Email, required: true },
enquiryType: { type: String },
message: { type: Types.Markdown, required: true },
createdAt: { type: Date, default: Date.now }
});
Enquiry.schema.pre('save', function(next) {
this.wasNew = this.isNew;
next();
});
Enquiry.schema.post('save', function() {
if (this.wasNew) {
this.sendNotificationEmail();
}
});
Enquiry.schema.methods.sendNotificationEmail = function(callback) {
var enqiury = this;
keystone.list('User').model.find().where('isAdmin', true).exec(function(err, admins) {
if (err) return callback(err);
new keystone.Email('enquiry-notification').send({
to: admins,
from: {
name: 'Wheatcroft Accounting',
email: 'contact#abc.com'
},
subject: 'New Enquiry for **',
enquiry: enqiury
}, callback);
});
};
Enquiry.defaultSort = '-createdAt';
Enquiry.defaultColumns = 'name, email, enquiryType, createdAt';
Enquiry.register();
This is the route file
var keystone = require('keystone'),
async = require('async'),
Enquiry = keystone.list('Enquiry');
exports = module.exports = function(req, res) {
var view = new keystone.View(req, res),
locals = res.locals;
locals.section = 'contact';
locals.formData = req.body || {};
locals.validationErrors = {};
locals.enquirySubmitted = false;
view.on('post', { action: 'contact' }, function(next) {
var newEnquiry = new Enquiry.model();
var updater = newEnquiry.getUpdateHandler(req);
updater.process(req.body, {
flashErrors: true,
fields: 'name, email, enquiryType, message',
errorMessage: 'There was a problem submitting your enquiry:'
}, function(err) {
if (err) {
locals.validationErrors = err.errors;
console.log(err);
} else {
locals.enquirySubmitted = true;
}
next();
});
});
view.render('contact');
}
I believe the problem has to do with the way KeystoneJS handles Types.Name field types internally.
In your jade file, you should reference your name field using a path to its virtual name.full property. Internally name.full has a setter that splits the name into name.first and name.last. So, if you wish to have separate input for the first and last name you should use name.first and name.last. If you want a single input to enter the full name you should use name.full.
Try replacing the input control for your name field:
input.form-control.input-box(type='text', name='name', value=formData.name, placeholder='Your Name')
with this:
input.form-control.input-box(type='text', name='name.full', value=formData['name.full'])
Related
i'm using Vue.js and Element Ui libraries for my project. I have front-end based validation with some rules. But i also need to implement display errors (for current field) from backend. When the form is sent and backend returns error it looks like this:
[
{"message": "email address is invalid", "path": ["email"]},
{"message": "example error for password field", "path": ["password"]}
]
where path is field name based on my form field model.
I created some extra element that displays error from backend as you can see in my fiddle. But i would like to use vue element ui validation. So backend errors should be displayed the same way as front-end messages. I can't figure out how to do this.
Here is my fiddle: https://jsfiddle.net/ts4Lfxb6/
Form code looks like this:
<el-form :model="loginForm" :rules="rules" ref="loginForm" label-position="top">
<el-form-item label="Email" prop="email">
<el-input v-model="loginForm.email" :disabled="formProcessing" ref="loginInput"></el-input>
<p v-if="isErrorForField('email', errors)">{{ getErrorForField('email', errors) }}</p>
</el-form-item>
<el-form-item label="Password" prop="password">
<el-input v-model="loginForm.password" :disabled="formProcessing" type="password"></el-input>
<p v-if="isErrorForField('password', errors)">{{ getErrorForField('password', errors) }}</p>
</el-form-item>
<el-form-item>
<div class="submit-wrapper">
<el-button type="primary" #click="submit('loginForm')" :loading="formProcessing">Log in</el-button>
</div>
</el-form-item>
</el-form>
And Full component is here:
var Main = {
data() {
return {
loginForm: {
email: '',
password: ''
},
rules: {
email: { required: true, message: 'Required', trigger: 'change' },
password: { required: true, message: 'Required', trigger: 'change' }
},
formProcessing: false,
errors: []
}
},
methods: {
isErrorForField (field, errors) {
if (!errors && !errors.length) {
return false
}
let filtered = errors.filter(error => {
return error.path[0] === field
})
if (filtered.length) {
return filtered
}
},
getErrorForField (field, errors) {
if (!errors && !errors.length) {
return false
}
let filtered = errors.filter(error => {
return error.path[0] === field
})
if (filtered.length) {
return filtered[0].message
}
},
supportGlobalErrorMessage () {
this.errors.forEach(error => {
if (!error.path.length) {
this.$message({
message: error.message,
type: 'error'
})
}
})
},
submit (formName) {
this.$refs[formName].validate(valid => {
if (!valid) {
return false
}
this.formProcessing = true
// send data to backend
// error response looks like this:
let errors = [
{"message": "email address is invalid", "path": ["email"]},
{"message": "example error for password field", "path": ["password"]}
]
setTimeout(() => {
this.formProcessing = false
this.errors = errors
this.supportGlobalErrorMessage()
}, 500)
})
}
}
}
var Ctor = Vue.extend(Main)
new Ctor().$mount('#app')
Can someone help?
Made the following changes to your code:
var Main = {
data() {
return {
loginForm: {
email: '',
password: ''
},
rules: {
email: {
required: true,
//validator: this.customValidator,
//trigger: 'blur'
},
password: {
required: true,
//validator: this.customValidator,
//trigger: 'blur'
}
},
formProcessing: false,
errors: []
}
},
methods: {
customValidator(rule, value, callback) {
console.log(rule)
if (!value) {
callback(new Error('The field is required'))
}
let errors = [{
"message": "email address is invalid",
"path": ["email"]
},
{
"message": "example error for password field",
"path": ["password"]
}
]
setTimeout(() => {
this.errors = errors
if (this.isErrorForField(rule.fullField, this.errors)) {
callback(new Error(this.getErrorForField(rule.fullField, this.errors)))
}
callback()
}, 500)
},
isErrorForField(field, errors) {
if (!errors && !errors.length) {
return false
}
let filtered = errors.filter(error => {
return error.path[0] === field
})
if (filtered.length) {
return filtered
}
},
getErrorForField(field, errors) {
if (!errors && !errors.length) {
return false
}
let filtered = errors.filter(error => {
return error.path[0] === field
})
if (filtered.length) {
return filtered[0].message
}
},
supportGlobalErrorMessage() {
this.errors.forEach(error => {
if (!error.path.length) {
this.$message({
message: error.message,
type: 'error'
})
}
})
},
submit(formName) {
this.$refs[formName].validate(valid => {
if (!valid) {
return false
}
this.formProcessing = true
// send data to backend
// error response looks like this:
let errors = [{
"message": "email address is invalid",
"path": ["email"]
},
{
"message": "example error for password field",
"path": ["password"]
}
]
setTimeout(() => {
this.errors = errors
this.formProcessing = false
this.supportGlobalErrorMessage()
}, 500)
})
}
}
}
var Ctor = Vue.extend(Main)
new Ctor().$mount('#app')
#import url("//unpkg.com/element-ui#2.0.5/lib/theme-chalk/index.css");
<script src="//unpkg.com/vue/dist/vue.js"></script>
<script src="//unpkg.com/element-ui#2.0.5/lib/index.js"></script>
<div id="app">
<el-form :model="loginForm" :rules="rules" ref="loginForm" label-position="top">
<el-form-item label="Email" prop="email" :error="getErrorForField('email', errors)">
<el-input v-model="loginForm.email" :disabled="formProcessing" ref="loginInput"></el-input>
<!-- <p v-if="isErrorForField('email', errors)">{{ getErrorForField('email', errors) }}</p> -->
</el-form-item>
<el-form-item label="Password" prop="password" :error="getErrorForField('password', errors)">
<el-input v-model="loginForm.password" :disabled="formProcessing" type="password"></el-input>
<!-- <p v-if="isErrorForField('password', errors)">{{ getErrorForField('password', errors) }}</p> -->
</el-form-item>
<el-form-item>
<div class="submit-wrapper">
<el-button type="primary" #click="submit('loginForm')" :loading="formProcessing">Log in</el-button>
</div>
</el-form-item>
</el-form>
</div>
The validator property in the rules attribute can set a custom validation rule which receive three parameters (rule, value, callback).
rule: The validation rule in the source descriptor that corresponds to the field name being validated. It is always assigned a field property with the name of the field being validated.
value: The value of the source object property being validated.
callback: A callback function to invoke once validation is complete. It expects to be passed an array of Error instances to indicate validation failure. If the check is synchronous, you can directly return a false or Error or Error Array.
So, you can get the data from the backend and process it, and then display the error message through the callback.
I am trying to have it so that when a user clicks a checkbox that the value is true but when they leave it unchecked it goes to false. I want it so they default to true. I have the following as part of my user model.
Part of my user model:
newsletterEmail: { type: Boolean, default: 'true'},
lowerLimitEmail: { type: Boolean, default: 'true'},
featuresEmail: { type: Boolean, default: 'true'},
assetOut180: { type: Boolean, default: 'true'},
lowerLimit: { type: Boolean, default: 'true'},
The HTML I have for the checkbox is:
<div class="form-check">
<label class="form-check-label">
<input class="form-check-input" name="newsletterEmail" type="checkbox" value="true">
Newsletter notifications
</label>
</div>
Then inside my route I have this query:
User.findById(req.user.id, function(err, user) {
if (err) return (err);
user.newsletterEmail = req.body.newsletterEmail || false;
user.lowerLimitEmail = req.body.lowerLimitEmail || false;
user.featuresEmail = req.body.featuresEmail || false;
user.assetOut180 = req.body.assetOut180 || false;
user.lowerLimit = req.body.lowerLimit || false;
user.save(function(err) {
if (err) return (err);
req.flash('success', { msg: 'Notification Settings Updated.' });
res.redirect(req.redirect.success);
});
});
What is wrong? I took the code from another route and modified it to see if I just wrote the basic part of the route wrong, I that part right, so I am pretty sure is has to do with the query.
I am using the Lodash and jQuery library inside my javascript and I am trying to figure out how to call a method that will allow me to truncate the results of a key value pair used to create a list inside my .html code. The html looks as follows:
<div class="slide-in-panel">
<ul class="list-unstyled slide-in-menu-navigation" data-bind="foreach: __plugins">
<li class="btn-block">
<div class="btn btn-default btn-block" data-bind="click: $parent.showPlugin, tooltip: 'Shoebox.Panel'">
<span data-bind="text: config.title"></span>
<em class="webgis-Icon webgis-Cross slide-in-menu-remove-shoebox-button"
data-bind="click: $parent.showRemoveConfirmBox, tooltip: 'Shoebox.RemoveShoebox'">
</em>
</div>
</li>
</ul>
</div>
The key component is the data-bind="text: config.title" part. This populates the list with name for that button. The config.title is created in the javascript file below. My goal is to apply a method such as .truncate() to the config.title part in the javascript to keep whatever name is being populated, from being to long. How would I do this?
return this.__backendShoeboxClient.createShoebox(this.__shoeboxName()).then((function(_this) {
return function(shoebox) {
return $when.join(shoebox.getName(), shoebox.getId(), shoebox.getUserName()).then(function(arg) {
var shoeboxId, shoeboxName, userName;
shoeboxName = arg[0], shoeboxId = arg[1], userName = arg[2];
return _this.__shoeboxContentFactory.create({
shoeboxId: shoeboxId,
shoeboxName: shoeboxName,
userName: userName
}).then(function(arg1) {
var activeShoeboxHandle, config, shoeboxContent;
shoeboxContent = arg1.shoeboxContent, activeShoeboxHandle = arg1.activeShoeboxHandle;
_this.__activeShoeboxHandleMain.loadModel(activeShoeboxHandle);
config = {
plugin: shoeboxContent,
title: shoeboxName,
userName: userName,
id: shoeboxId,
handle: activeShoeboxHandle,
icon: ""
};
_this.add(config, null, null);
activeShoeboxHandle.loadModel(shoebox);
_this.__shoeboxName.useDefaultValue();
return _this.__shoeboxName.clearError();
});
})["catch"](function(error) {
__logger__.error("Error while calling request " + error);
return $when.reject(new Error("Error while calling request. " + error));
});
};
})(this));
};
I am also trying to use the knockout style binding like this, but without any success:
<span data-bind="style: { textOverflow: ellipsis }, text: config.title"></span>
This should do it:
Use the truncate function like this: config.title = _.truncate(config.title, {'length': maxLength});
return this.__backendShoeboxClient.createShoebox(this.__shoeboxName()).then((function(_this) {
return function(shoebox) {
return $when.join(shoebox.getName(), shoebox.getId(), shoebox.getUserName()).then(function(arg) {
var shoeboxId, shoeboxName, userName;
shoeboxName = arg[0], shoeboxId = arg[1], userName = arg[2];
return _this.__shoeboxContentFactory.create({
shoeboxId: shoeboxId,
shoeboxName: shoeboxName,
userName: userName
}).then(function(arg1) {
var activeShoeboxHandle, config, shoeboxContent;
shoeboxContent = arg1.shoeboxContent, activeShoeboxHandle = arg1.activeShoeboxHandle;
_this.__activeShoeboxHandleMain.loadModel(activeShoeboxHandle);
config = {
plugin: shoeboxContent,
title: shoeboxName,
userName: userName,
id: shoeboxId,
handle: activeShoeboxHandle,
icon: ""
};
config.title = _.truncate(config.title, {'length': 15});
_this.add(config, null, null);
activeShoeboxHandle.loadModel(shoebox);
_this.__shoeboxName.useDefaultValue();
return _this.__shoeboxName.clearError();
});
})["catch"](function(error) {
__logger__.error("Error while calling request " + error);
return $when.reject(new Error("Error while calling request. " + error));
});
};
})(this));
};
So, for edification's sake, I was able to find a solution to this problem using the substring method inside a simple if statement. The issue seemed to be that I was putting this in the wrong part of my code so I want to clarify what worked for me for future readers. I was able to apply the following inside the key: value pair and it totally worked:
config =
plugin: shoeboxContent
title: if name.length > 24
"#{name.substring 0, 24}..."
else
name
userName: shoebox.getUserName()
id: shoebox.getId()
handle: activeShoeboxHandle
icon: ""
#add config, null, null
I am trying to figure out how it is possible to pass an array as the value for the property of an instance. I currently have the dataType set to STRING in my model and have values from jQuery fields insert each form field value into an array that I parse from the body and set to the property, discoverSource. Unfortunately I receive a string violation error that says I can't use an array or object. What does this mean and how can I change the dataType of the field or route to allow me to pass the comma separated values to the field?
E.x. For discoverySource I pass values to two fields (NJ, NY). On submit, the values are combined in an array as ["NJ", "NY"] and the error displays:
Error Message:
{"name":"SequelizeValidationError","message":"string violation: discoverySource cannot be an array or an object","errors":[{"message":"discoverySource cannot be an array or an object","type":"string violation","path":"discoverySource","value":["NJ","NY"]}]}
Here is my model:
module.exports = function(sequelize, DataTypes) {
var Organization = sequelize.define('organization', {
organizationId: {
type: DataTypes.INTEGER,
field: 'organization_id',
autoIncrement: true,
primaryKey: true
},
organizationName: {
type: DataTypes.STRING,
field: 'organization_name'
},
admin: DataTypes.STRING,
discoverySource: {
type: DataTypes.TEXT,
field: 'discovery_source'
},
members: DataTypes.STRING
},{
freezeTableName: true,
classMethods: {
associate: function(db) {
Organization.belongsToMany(db.User, { through: 'member', foreignKey: 'user_id' });
},
},
});
return Organization;
}
Here is the route:
var express = require('express');
var appRoutes = express.Router();
var passport = require('passport');
var localStrategy = require('passport-local').Strategy;
var models = require('../models/db-index');
appRoutes.route('/sign-up/organization')
.get(function(req, res){
models.User.find({
where: {
user_id: req.user.email
}, attributes: [ 'user_id', 'email'
]
}).then(function(user){
res.render('pages/app/sign-up-organization.hbs',{
user: req.user
});
})
})
.post(function(req, res, user){
models.Organization.create({
organizationName: req.body.organizationName,
admin: req.body.admin,
discoverySource: req.body.discoverySource
}).then(function(organization, user){
res.redirect('/app');
}).catch(function(error){
res.send(error);
console.log('Error at Post' + error);
})
});
Here is my view file:
<!DOCTYPE html>
<head>
{{> head}}
</head>
<body>
{{> navigation}}
<div class="container">
<div class="col-md-6 col-md-offset-3">
<form action="/app/sign-up/organization" method="post">
<p>{{user.email}}</p>
<input type="hidden" name="admin" value="{{user.email}}">
<input type="hidden" name="organizationId">
<label for="sign-up-organization">Company/Organization Name</label>
<input type="text" class="form-control" id="sign-up-organization" name="organizationName" value="" placeholder="Company/Organization">
Add Another Discovery Source
<div id="sign-up-organization-discovery-source">
<input type="text" id="discovery-source-field" placeholder="Discovery Source" name="discoverySource[0]">
</div>
<br />
<button type="submit">Submit</button>
</form>
Already have an account? Login here!
</div>
</div>
<script type="text/javascript">
$(function() {
var dataSourceField = $('#sign-up-organization-discovery-source');
var i = $('#sign-up-organization-discovery-source p').size();
var sourceCounter = 1;
$('#sign-up-add-discovery-source').on('click', function() {
$('<p><label for="discovery-source-field"><input type="text" id="discovery-source-field" size="20" name="discoverySource['+ sourceCounter++ +']" value="" placeholder="Discovery Source" /></label> Remove</p>').appendTo(dataSourceField);
i++;
return false;
});
$('#sign-up-organization-discovery-source').on('click', '.remove', function() {
if (i > 1) {
$(this).parent('p').remove();
i--;
}
return false;
});
});
</script>
</body>
To answer the last comment, I need to be able to make the code more readable, so I'm posting it here in a new answer.
Having thought about it a little more, it would make more sense to add it as custom 'getter' function. I'll also include the 'instanceMethods' to demonstrate how that works, as well.
var Organization = sequelize.define('organization', {
...
},{
freezeTableName: true,
classMethods: {
associate: function(db) {
Organization.belongsToMany(db.User, { through: 'member', foreignKey: 'user_id' });
},
},
// Here's where custom getters would go
getterMethods: {
discoverySources: function() {
return this.getDataValue('discoverySource');
}
},
// here's the instance methods
instanceMethods: {
getSourcesArray: function() {
return this.getDataValue('discoverySource');
}
}
});
Both of these options add the functions to each instance created by the Model. The main difference being in how they are accessed.
organization.discoverySources; // -> ['s1', 's2', etc...]
organization.getSourcesArray(); // -> ['s1', 's2', etc...]
note the additional () required on the instanceMethod. Those are added as functions of the instance, the getterMethods get added as properties.
setterMethods work the same way to allow you to define custom setters.
Hope that clarifies things a bit.
I have a model User. The model currently works with a Register view to 'register' a new user.
User:
var User = Backbone.Model.extend({
url: '/user',
defaults: {
first_name: '',
last_name: '',
email: '',
username: '',
password: ''
},
parse: function(response){
if(response.username) {
this.trigger('username_check',response.username);
}
if(response.email) {
this.trigger('email_check',response.email);
}
},
validate: function(attrs) {
var email_filter = /^([a-zA-Z0-9_\.\-])+\#(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/;
var username_filter = /^([a-zA-Z0-9]){0,1}([a-zA-Z0-9])+$/;
errors = [];
if (attrs.first_name == '')
errors.push({name: 'first_name', error: 'Please enter your First Name'});
if (attrs.last_name == '')
errors.push({name: 'last_name', error: 'Please enter your Last Name'});
if (!email_filter.test(attrs.email))
errors.push({name: 'email', error: 'Please enter a valid email address'});
if (!username_filter.test(attrs.username))
errors.push({name: 'username', error: 'Your username contains invalid characters. Usernames may only contain letters and numbers.'});
if (attrs.username == '')
errors.push({name: 'username', error: 'Please provide a valid username'});
if (attrs.username.length > 12)
errors.push({name: 'username', error: 'Your username must be less than 12 characters'});
if (attrs.username.length < 4)
errors.push({name: 'username', error: 'Your username must be at least 4 characters'});
if (attrs.password == '')
errors.push({name: 'password', error: 'Please provide a password.'});
if (attrs.password.length < 5)
errors.push({name: 'password', error: 'Your password must be at least 5 characters in length.'});
if(errors.length > 0)
return errors;
}
});
View:
var Register = Backbone.View.extend({
initialize: function() {
this.user = new User;
this.first_name = this.$('input[name="first_name"]');
this.last_name = this.$('input[name="last_name"]');
this.email = this.$('input[name="email"]');
this.username = this.$('input[name="username"]');
this.password = this.$('input[name="password"]');
this.confirm_password = this.$('input[name="confirm_password"]');
this.redirect_url = $(this.el).attr('data-redirect-url');
},
events: {
'submit form' : 'onSubmit',
'blur input[name="username"]' : 'checkUsernameExists',
'blur input[name="email"]' : 'checkEmailExists'
},
checkUsernameExists: function(e) {
var self = this;
if(this.username.val().length > 3) {
this.user.fetch({data: {username : this.username.val(), check : 'true'}});
this.user.on("username_check", function(status){
if(status == 'unavailable') {
self.processErrors([{name: 'username', error: 'This username is already taken, please try another.'}]);
} else {
$('input[name="username"]').closest('.controls').find('div.control-error').empty();
}
})
}
},
checkEmailExists: function(e) {
var self = this;
var email_filter = /^([a-zA-Z0-9_\.\-])+\#(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/;
if (email_filter.test(this.email.val())) {
this.user.fetch({data: {email : this.email.val(), check : 'true'}});
this.user.on("email_check", function(status){
if(status == 'unavailable') {
self.processErrors([{name: 'email', error: 'This email is already used. Please login to your account or use a different email.'}]);
} else {
$('input[name="email"]').closest('.controls').find('div.control-error').empty();
}
})
}
},
onSubmit: function(e) {
var self = this;
e.preventDefault();
var attrs = {
'first_name': this.first_name.val(),
'last_name': this.last_name.val(),
'email': this.email.val(),
'username': this.username.val(),
'password': this.password.val()
};
$('div.control-error').html('');
var user = this.user.set(attrs, {
error: function(model, response) {
self.processErrors(response);
}
});
if(user) {
errors = [];
if (self.confirm_password.val() == '')
errors.push({name: 'confirm_password', error: 'Please confirm your password.'});
else if (self.confirm_password.val() !== self.password.val())
errors.push({name: 'confirm_password', error: 'Your passwords do not match. Please confirm your passwords.'});
if(errors.length > 0) {
self.processErrors(errors);
} else {
user.save(this.attrs, {
success: function(model, response){
window.location.href = self.redirect_url;
}});
}
}
},
processErrors: function(response) {
for (var key in response) {
if (response.hasOwnProperty(key)) {
field = response[key];
$('input[name="'+field.name+'"]').closest('.controls').find('div.control-error').html(field.error);
}
}
}
});
Now I want to handle the Login view. Should I use the same model? Considering it validate methods that are irrelevant to the login view (Email/Pass).
Is there a best practice or recommended way for handling this? I'm using backbone primarily for code separation - it's not an all ajax app, only the form handling is ajax, then it redirects to a new page upon success. The is the flow of the site.
Any suggestions/recommendations would be great for how to handle validation and various interactions with a model like this, for Registering a user to Logging in a user.
I'm thinking of creating a new model UserLogin - but not sure if that would be best.
You don't need a model for login. Have the view validate the form and just make a post request.