Backbone Validation firing multiple times - backbone.js

I'm wondering why the Validate method on my model runs multiple times when I add a model to a collection.
Even if I strip my model Validation right down to this...
Client.Model = Backbone.Model.extend ({
validate : function(attrs) {
if ( !attrs.first_name ){
return 'Required';
}
}
});
If I console.log() from inside the validate method I can see that it's been called 5 times. the first two validate successfully, the third fails, and then the 4th and 5th also pass (and subsequently it syncs correctly on the server)
This is creating a problem because I'm building a custom message plugin and it's being called all 5 times that the validation occurs.
I know it will correctly be called when I create a new model and retrieve models from the server. But what I cannot understand is this 'third' call to validate that always fails. (btw, I've managed to figure out that it is NOT a server issue)
I'm wondering what i'm missing here..
Thanks in advance.
:)
JSBIN - http://jsbin.com/ucowoq/2/edit
Check the console, obviously there's an error with the POST, but it shows the validate method running 5 times, on my app, it fails to validate on the 3rd every time! The server only ever returns a 500 error or the JSON for the created model.
Hope this helps anyone looking over this.
EDIT :
I've come up with this hack to get everything working correctly. I'm still not happy with the validate method being called 5 times, but because the 1 occurrence that caused the validation to fail contained an object with key & 'undefined' values, I'm just checking for that before returning anything. This allows me to implement my 'message' plugin as I can now retrieve errors at the correct time.
validate: function( attrs ){
if (attrs.first_name !== undefined){
if (!attrs.first_name)
return 'first name required';
}
}

The line that causes this confusion here is this: Backbone 0.9.9 Line 411 It clears the model's attributes before setting them again.
Why does it matter though? It will fail to validate, true, but the result of that validation is never used anywhere, so you shouldn't need that check for undefined in your edit.

Related

How to access mongoose populated fields?

I'm not able to access the populated fields of mongoose objects. I want to output it in my page.
Example:
"console.log(booking.assignedUser.first)" gives me back:
TypeError: Cannot read properties of undefined (reading 'first')
But from what I can tell, this should be working. The field is clearly there.
In my jsx file:
console.log(booking.assignedUser)
Object:
{
etc etc
assignedUser: { _id: new ObjectId("62f068b068802d58c8d35442"), first: 'driver' },
etc etc
}
So why I can access booking.assignedUser and it shows me the data, but booking.assignedUser.first doesn't work?
Because these values are being populated from the DB, I guess they aren't loading fast enough so it's giving me this error.
If I check to make sure the value exists first, then use it, it's working.
I'm working with a lot of this type of data in my app, so instead of outputting the jsx directly in the react object, I'm using a function to return it all for me which I pass in the db data.
using a ternary at the beginning of the output within the React component was not good enough, for example.
{ data ?
<Form>
<SomeStuffHere>
<SomeMoreStuffHere>
<Form.Control> {data.something} </Form.Control>
</Form>
: '' }
This was not good enough. It would still error out. I had to place the ternary immediately on the field in order for it to work.
Doing this for every single field would be a pain in the ass, so putting it into a function first seems to work better.
Probably , you are trying to achieve data's populates when data didn't set yet. Need to be sure data is set already.
You can use it like ;
booking.assignedUser && console.log(booking.assignedUser.first)
If the page can't view components due to data is empty, need to use this condition beginning of view component.
data.length > 0 && ...</Component/>

How can I call validate on no change in Backbone?

Set data that will fail validation
Model.set({phoneNumber : 'meow meow'})
Validation that applies a border color
validate: function(attr){
if(attr.phoneNumber){
var phoneNumber = attr.phoneNumber,
regex = /^\([0-9]{3}\)\s[0-9]{3}-[0-9]{4}/;
if(!regex.test(val)){
View.showError('businessNumber');
}
}
Later the user focus on the input field, I remove the error styling
The user doesn't change anything and the blur event is fired
Validation doesn't run because nothing changed.
Do not reference your view directly from your model. This is a completely deep and fundamental violation of the core tenet of the Model/View/* design. When you call set and validation fails, the model will emit an error event (as of Backbone 0.9.9) which your view should listen for and respond to by updating the view accordingly. You may also alternately pass a callback to set to handle the error, but events are the better choice in most situations. Note that your model needs to actually return an error object from validate, which will refuse to update the data, so after the user fixes the input and blur occurs, the data will actually change. With your code as is, Backbone thinks the validate call succeeded since no error is returned.
In your view, here's some pseudocode showing how to translate the model's error object into UI warnings:
initialize: function () {
_.bindAll(this);
this.model.on('error', this.showError);
},
showError: function (error) {
if (error.businessNumber) {
this.$businessNumber.addClass('error');
}
}
As a side note, don't feel bad about being confused with how to use backbone for forms. The fact that out of the box set won't accept invalid data is a huge stumbling block and non-intuitive. There are plugins to help with both forms and validation (https://github.com/documentcloud/backbone/wiki/Extensions,-Plugins,-Resources), but out of the box this is not one of the obvious/easy parts of backbone.

Backbone.js model validate method fails to fire

I'm trying to understand how Backbone.js model validation works, but I'm seeing some odd inconsistencies. In one place in my app, the validate method is getting called as expected. In another place, however, Backbone.js seems to be passing in a { silent: true } object to the validator, even though I don't want it to.
Here's a jsFiddle that illustrates the issue. The validate method should be called When the Copy buttons are clicked or the values change, but when I step through the code it's clear that the _validate function is being passed the { silent: true } option.
What am I missing?
Update: Figured out what was going on here. I created this jsFiddle originally to replicate an issue I was having that was actually the opposite of this question--I was trying to add an empty model to a collection and validation was firing and preventing me from doing so. When I made the Fiddle, though, it worked as I wanted my app to work. Validation wasn't firing when an empty model was added. I couldn't figure out the difference.
Turns out I was using Backbone.js 0.9.0 in my application and version 0.9.1 in my jsFiddle. Jeremy made changes to validation in 0.9.1 to make it work the way I wanted it to work in my app (see this issue on GitHub). Mystery solved.
Backbone specifically does not call _validate when you're making a new model.
Jeremy suggests that you do:
var mymodel = new MyModel();
mymodel.set({params});
Here's our exchange on github: can't override silent:true
From the Backbone docs, it seems you have to either call set or save on the model in order for validate to trigger.
I updated the jsfiddle so that set is called, and the now the validation function gets triggered:
http://jsfiddle.net/J3uuH/12/

Handling the model-update-server response in Backbone.js

The Backbone.js model updates itself - and its views - locally on the page before
passing the data to the server and checking the server's response, so if the
server says "sorry charlie that's no good" the page has already shown the data
as having changed and thus doesn't correctly represent the server-side state of the object. What's the correct/elegant way to handle this on the Backbone.js side when the server returns an error?
If you are directly editing a model and trying to sync it, and also using it elsewhere in your app simultaneously, then that can lead to a world of problems.
In many cases it is better to clone the model for editing, and then when it syncs successfully, apply the clone's attributes back on to the original model.
You can get a cloned model by simply calling:
var clonedModel = originalModel.clone();
And then you can apply the attributes back in a success handler like
originalModel.set(clonedModel.attributes)
How about passing success, error callback functions to the statement where you update the server side state. May be something like this....
this.model.save(
{}, {
success: function() {
/* update the view now */
},
error: function() {
/* handle the error code here */
}
});
Taking it a level higher, you might override the Backbone.sync to globally handle the server-side error codes.
Use
model.save({wait: true});
Source: http://backbonejs.org/#Model-save

Ext JS - Can I 'chain' methods on a field?

HI,
I am just trying to set a field value and disable it at the same time.
Can this be done in ext js? The docs are very weak on this subject.
something like this generates errors:
myForm.getForm().findField('start_date').setValue('').setDisabled(true);
I'm used to JQuery which does this sort of thing nicely but haven't had luck with Ext.
Thanks for any help.
Actually, Field.setValue does in fact return a reference to the field (docs), so you should be able to call setDisabled (inherited from Component) as you have it. You must have some other issue going on. Maybe findField('start_date') is returning null. You have to make sure all the return values are what you expect. Use Firebug to figure out the error, or break apart your statement and see which call is actually failing.
Anything is "chainable" as long as the return value is the object itself (usually denoted as this in the docs). In jQuery, everything operates on DOM elements, so it is consistent. In Ext, you have lots of components with various behaviors. Sometimes chaining makes sense, sometimes it does not -- just make sure you check the docs when you aren't sure.
i agree with bmoeskau it should work if the field is there and found by the form. I would advise you to to it something like that to prevent errors:
var field = myForm.getForm().findField('xyz');
if(field !== undefined)
{
field.setValue('');
field.setDisabled(true);
}
else
{
// Error Handling
}
This is because setValue() method doesn't return field object. You cannot use setDisabled() in such way.
EDIT: (For those down-voting morons)
From ExtJS documentation:
method: setValue(value)
Parameters:
value : Mixed
The value to set
Returns:
void

Resources