Set model attribute during validation in Backbone - javascript

I have a model as
var Info = Backbone.Model.extend({
url: '',
defaults: {
username: '',
email: '',
error: ''
},
initialize: function(){
console.log('Obj created');
},
validate: function(attr){
if(!attr.username){
attr.error = 'Username cannot be empty';
}
}
});
View
var model = new Info();
var View1 = Backbone.View.extend({
model: model,
initialize: function(){
this.render();
},
render: function(){
var template = _.template($('#App1').html());
this.$el.html(template);
},
'events': {
'click #btn1': 'submit'
},
submit: function(){
var obj = {
username: $('#username').val(),
email: $('#pwd').val)
};
this.model.save();
}
});
Here I want to set model.set({error: 'Message goes here'}) during validate event.
However, validate only returns true / false. Is there a way we can set the value in the validate method.

You can set an error property inside validate() function:
this.set('error', 'Message goes here')
Once set, error message will be accessible via this.model.get('error') from within view object code.

Related

Backbone validation plugin does not validate

I am using Backbone.Validation plugin to validate a simple form. Below is my model
var BuyerModel = Backbone.Model.extend({
defaults: {
name: '',
age: ''
},
validation: {
name: {
required: true
},
age: {
min: 18
}
},
initialize: function () {
_.extend(Backbone.Model.prototype, Backbone.Validation.mixin);
}
});
Below is my view
var BuyerModelFormView = Backbone.View.extend({
events: {
'click [name~="save"]': 'save'
},
initialize: function () {
Backbone.Validation.bind(this);
},
template: _.template('\
<form>\
Enter name:\
<input name="name" type="text" value="<%= name %>"><br>\
Enter age:\
<input name="age" type="text" value="<%= age %>"><br>\
<input type="button" name="save" value="Save">\
</form>\ '),
render: function () {
var html = this.template(this.model.toJSON());
$(this.el).html(html);
},
save: function () {
console.log(this.model.toJSON());
this.model.set({
name: $('[name~="name"]').val(),
age: $('[name~="age"]').val()
});
console.log(this.model.toJSON());
}
});
Here is how I am using it
var buyerModel = new BuyerModel();
var buyerModelFormView = new BuyerModelFormView({
model: buyerModel,
el: 'body'
});
buyerModelFormView.render();
When I enter anything in the form and hit enter it updates model but does not validate. Even if I enter incorrect value model still gets update.
What am I doing wrong and how can I solve this?
Set force validation like this
this.model.set({
name: $('[name~="name"]').val(),
age: $('[name~="age"]').val()
}, {validate: true});
Is it what you want?
Because Model.set has such string
// Run validation.
if (!this._validate(attrs, options)) return false;
And
// Run validation against the next complete set of model attributes,
// returning `true` if all is well. Otherwise, fire an `"invalid"` event.
_validate: function(attrs, options) {
if (!options.validate || !this.validate) return true;
So if you didn't pass validate - it will be ignored
Check in such way
$(function(){
var buyerModel = new BuyerModel();
buyerModel.on('change', function(){
console.log('on change', arguments);
});
var buyerModelFormView = new BuyerModelFormView({
model: buyerModel,
el: 'body'
});
buyerModelFormView.render();
});

Backbone localStorage Adapter: Uncaught Error: A "url" property or function must be specified

I've gone over the other posts on the same topic and perhaps I'm missing something in my own code but it seems to me things should be working. I've never worked with localStorage and backbone and seem to be missing something here. Any thoughts are greatly appreciated!
my instances:
var Address = {
run: function() {
this.router = new AddressRouter();
this.contactscollection = new AddressCollection();
this.addContact = new AddressAddView();
this.listView = new AddressListView();
Backbone.history.start();
}
};
my collection:
var AddressCollection = Backbone.Collection.extend({
model: AddressModel,
localstorage: new Store('backbone-addressbook')
});
my model:
var AddressModel = Backbone.Model.extend({
defaults: {
id: '',
name: '',
email: ''
}
});
and my view:
var AddressAddView = Backbone.View.extend({
el: '#content',
template: _.template($('#addContactTemplate').html()),
events: { 'submit form#addContactForm': 'createContact'},
createContact: function(){
Address.contactscollection.create(this.newAttributes());
this.save();
this.input.val('');
},
newAttributes: function() {
return {
id: $('#id').val(),
name: $('#name').val(),
email: $('#email').val()
}
},
initialize: function() {
_.bindAll(this, 'addContactPage','render');
},
addContactPage: function(id) {
var contact = {},
model = Address.contactscollection.get(id);
if (id !== undefined && model !== undefined) {
contact = model.toJSON();
}
this.$el.html(this.template({contact: contact}));
}
});
Case matters.
localstorage: new Store('backbone-addressbook')
needs to be
localStorage: new Store('backbone-addressbook')
If localStorage isn't set, your collection is assumed to persist to a RESTful API, and a url is required.

How do I validate a form being filled out in Backbone?

So I have a new form set up it saves temporarily and all but I want it to only be able to update when it is validated otherwise show some errors. This is during the view section for the saveEdits event Any clue as to what I am doing wrong?
This is my main.js file
(function () {
window.App = {
Models: {},
Collections: {},
Views: {},
Templates: {},
Router: {}
};
// MODEL
App.Models.User = Backbone.Model.extend({
defaults: {
firstName: 'first',
lastName: 'last',
email: 'Email',
phone: '222',
birthday: '07/22/1980'
},
validate: function (attrs) {
if (!attrs.firstName) {
return 'You must enter a real first name.';
}
if (!attrs.lastName) {
return 'You must enter a real last name.';
}
if (attrs.email.length < 5) {
return 'You must enter a real email.';
}
if (attrs.phone.length < 10 && attrs.phone === int) {
return 'You must enter a real phone number, if you did please remove the dash and spaces.';
}
if (attrs.city.length < 2) {
return 'You must enter a real city.';
}
},
initialize: function() {
this.on('invalid', function (model, invalid) {
console.log(invalid);
});
}
});
//var userModel = new App.Models.User();
//VIEW
App.Views.User = Backbone.View.extend({
el: '#user',
//model: userModel,
//tagName: 'div',
//id: 'user',
//className: 'userProfile',
//template: _.template($("#userTemplate").html()),
//editTemplate: _.template($("#userEditTemplate").html()),
initialize: function (){
},
render: function() {
this.template = Handlebars.compile($("#userTemplate").html());
this.editTemplate = Handlebars.compile($("#userEditTemplate").html());
this.$el.html(this.template(this.model.toJSON()));
return this;
},
events: {
'click button.edit': 'editProfile',
'click button.save': 'saveEdits',
'click button.cancel': 'cancelEdits'
},
editProfile: function () {
this.$el.html(this.editTemplate(this.model.toJSON()));
},
saveEdits: function () {
var form = $(this.el).find('form#updateUser');
this.model.set({
firstName : form.find('.firstName').val(),
lastName : form.find('.lastName').val(),
email: form.find('.email').val(),
phone: form.find('.phone').val(),
birthday: form.find('.birthday').val()
});
this.model.validate();
this.render();
},
cancelEdits: function() {
this.render();
}
});
//start history service
Backbone.history.start();
var user = new App.Views.User({model: new App.Models.User()});
user.render();
})();
It works fine until I insert the this.model.validate and an error shows up stating this:
Uncaught TypeError: Cannot read property 'firstName' of undefined
You don't call validate explicitly -- it's meant called by the Backbone framework:
By default validate is called before save, but can also be called before set if {validate:true} is passed.
So to fix the code in the OP, use validate: true in the call to set:
this.model.set({
firstName : form.find('.firstName').val(),
// ...
}, { validate: true });
Note that, if you wanted to call validate, then you have to pass it the attrs parameter, as in this.model.validate(this.model.toJSON());

Backbone.js model.isValid() method not returning false for an invalid model

so I am trying to get the validate from my model to actually disable the save button but to re-validate when new input is included. Anyone know the best way to attempt this. Thanks! The problem I have with my method is that once it is disabled it doesn't return in state.
Here is the main.js file
(function () {
window.App = {
Models: {},
Collections: {},
Views: {},
Templates: {},
Router: {}
};
// MODEL
App.Models.User = Backbone.Model.extend({
defaults: {
firstName: 'first',
lastName: 'last',
email: 'Email',
phone: '222',
birthday: '07/22/1980'
},
validate: function (attrs) {
if (!attrs.firstName) {
return 'You must enter a real first name.';
}
if (!attrs.lastName) {
return 'You must enter a real last name.';
}
if (attrs.email.length < 5) {
return 'You must enter a real email.';
}
if (attrs.phone.toString().length < 10 ) {
//&& attrs.phone === int
return 'You must enter a real phone number, if you did please remove the dash and spaces.';
}
// if (attrs.birthday.length < 2) {
// return 'You must enter a real city.';
//}
},
initialize: function() {
this.on('invalid', function (model, invalid) {
console.log(invalid);
alert(invalid);
});
}
});
//var userModel = new App.Models.User();
//VIEW
App.Views.User = Backbone.View.extend({
el: '#user',
//model: userModel,
//tagName: 'div',
//id: 'user',
//className: 'userProfile',
//template: _.template($("#userTemplate").html()),
//editTemplate: _.template($("#userEditTemplate").html()),
initialize: function (){
},
render: function() {
this.template = Handlebars.compile($("#userTemplate").html());
this.editTemplate = Handlebars.compile($("#userEditTemplate").html());
this.$el.html(this.template(this.model.toJSON()));
return this;
},
events: {
'click button.edit': 'editProfile',
'click input.save': 'saveEdits',
'click button.cancel': 'cancelEdits'
},
editProfile: function () {
this.$el.html(this.editTemplate(this.model.toJSON()));
},
saveEdits: function () {
var form = $(this.el).find('form#updateUser');
this.model.set({
firstName : form.find('.firstName').val(),
lastName : form.find('.lastName').val(),
email: form.find('.email').val(),
phone: form.find('.phone').val(),
birthday: form.find('.birthday').val()
}, {validate: true} );
if(!this.model.isValid()) {
console.log('run');
$('.save').attr("disabled", "disabled");
} else {
console.log('run2');
alert('Changes have been made.');
$('.save').removeAttr("disabled");
return this.render();
}
},
},
cancelEdits: function() {
this.render();
}
});
//start history service
Backbone.history.start();
var user = new App.Views.User({model: new App.Models.User()});
user.render();
})();
And here is the Jade File:
extends layout
block content
div.centerContent
h4 User goes here with equal before it no space
div#user
p #{firstName} #{lastName}
p #{email}
p #{phone}
p #{birthday}
button.edit Edit
script(id="userTemplate", type ="text/template")
p {{firstName}} {{lastName}} 1
p {{email}} 2
p {{phone}} 3
p {{birthday}} 4
button.edit Edit
script(id="userEditTemplate", type ="text/template")
div
form(action="#")#updateUser
input(type="text", class="firstName", value='{{firstName}}')
input(type="text", class="lastName", value='{{lastName}}')
input(type="email", class="email", value='{{email}}')
input(type="number", class="phone",, value='{{phone}}')
input(type="date", class="birthday", value='{{birthday}}')
input(type="submit", value="Save").save Save
button.cancel Cancel
hr
script(type="text/javascript", src="/js/main.js")
The problem here is that you're calling the { validate: true } option to your model.set method, then you're subsequently calling model.isValid().
When you call model.set with the validate option set to true, Backbone.js will not set the properties you pass unless they all pass validation. So, by the time you call model.isValid() the model has been changed back to the previous version (before the .set call). model.isValid() automatically calls the model.validate() method and passes the current attributes of the model to it.
In your example, the values being passed to validate by the isValid method are the current (valid) attributes of your model. Because of this, isValid() is always going to validate to true. Which will cause you to never reach your else clause.
The solution here is instead of calling isValid to see if your model is valid (after passing validate: true to the set method) check the value of model.validationError. If model.validationError is a truthy value, then you know your model is invalid.
Here's a JSFiddle with an example of how to do that, with some documentation.

why wont validate fire the error - backbone.js

Why won't validate fire the error as "fred" should make the validate condition return true when it is set?
Person = Backbone.Model.extend({
initialize: function () {
console.log('inisialize Person');
this.bind("change:name", function () {
console.log(this.get('name') + ' is now the name value')
});
this.bind("error", function (model, error) {
console.log(error);
});
},
defaults: {
name: '',
height: ''
},
validate: function (attributes, options) {
if (attributes.name == "fred") { //why wont this work?
return "oh no fred is not allowed";
}
}
});
//var person = new Person({ name: 'joe', height: '6 feet' });
var person = new Person();
person.set({ name: 'fred', height: '200' });
Your validate() is called when saving, but not when setting an attribute unless you explicitly tell it to do so. From the docs:
By default validate is called before save, but can also be called
before set if {validate:true} is passed.
Try this: In the initialize(), change the this.bind('error') to this.on('invalid') The 'error' event is for failures at the server, after when calling save(). The 'invalid' is for validation errors on the client side. Lastly, add {validate: true} as a second argument to the person.set() calls. Backbone doesn't validate set() by default.
Person = Backbone.Model.extend({
defaults: {
name: '',
height: ''
},
validate: function(attributes) {
if(attributes.name === 'fred' )
return 'oh no fred is not allowed';
},
initialize: function() {
alert('welcome');
this.on('invalid', function(model, error){
alert(error);
});
//listeners
this.on('change:name', function(model) {
var name = model.get('name');
alert('changed ' + name);
});
});
var person = new Person();
person.set({ name: 'fred', height: '200' }, {validate: true}); //oh no fred is not allowed

Categories

Resources