Question

What's wrong with the following code?

(function(){

    window.App = {
        Models: {},
        Collections: {},
        Views: {}
    };

    window.template = function(id) {
        return _.template($('#' + id).html());
    };

    App.Models.Task = Backbone.Model.extend({
        defaults:{
            title: '',
            priority: 0
        },

        validate: function(attrs, options){
            if (attrs.priority < 0){
                return 'Priority cannot be negative.';
            }
        }
    });

    var task = new App.Models.Task ({ title: 'Sample Task', priority: 5 });
    task.on('invalid', function(model, error) { console.log(error); })

    task.save({ priority: -9 }); // Should not pass validation
    console.log(task.validationError); // Prints a validation error

    console.log(task.toJSON()); // Model is updated with -9
    console.log(task.isValid()); // false
})();

Output:

Priority cannot be negative. app.js:27
Priority cannot be negative. app.js:30
Object {title: "Sample Task", priority: -9} app.js:32
Priority cannot be negative. app.js:27
false 

I am currently watching a video tutorial and it's based on old version of backbone.js where validation was by default enforced on the set method. But in the current version validation is by default enforced on the save method.

But even though it's not a valid value and the validation doesn't pass why is it still setting the value to -9. Isn't it supposed to not set the value when the validation doesn't pass?

Was it helpful?

Solution 2

With the new version, when saving new data, you need to pass the validation option:

task.save({ priority: -9 }, {validation: true});

OTHER TIPS

in the current version of Backbone.js:

By default validate is called before save, but can also be called before set if {validate:true} is passed.

So, in order to have this method called on your method, you should set validate to true when setting a property on your model like so:

yourmodel.set('someproperty', 14, {validate: true});

I hope my answer was helpful.

This is an issue with the code from the official site. Looking at the source of save function I understand that presetting of options.validate to true happens AFTER the set is called.

You can try to switch the order of lines (in save function of Model):

  if (attrs && (!options || !options.wait) && !this.set(attrs, options)) return false;

  options = _.extend({validate: true}, options);

to:

   options = _.extend({validate: true}, options);

   if (attrs && (!options || !options.wait) && !this.set(attrs, options)) return false;

but I am not sure it won't break something else.

OR you can use the code from GitHub repo - there is a change that solves this.

Ok, you simply need to set the flag 'wait' to true OR set the 'validate' flag to true. How is it? Well, if you don't set the wait flag to true, the set method will be called with the options you passed the save method BEFORE the validation. So as you didn't need to pass the validate flag, the set method doesn't receive it, don't run the validation, and set the attributes.
As the doc isn't clear about the wait flag: your server will still receive the updated data.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top