Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use Backbone.Model.save() promise with validation

I'm trying to use the promise returned from Backbone.model.save(). Actually, per spec, it returns a promise if valid and false if not. I'd like to use the return value, regardless of the type, in future deferred.done() and deferred.fail() calls. Like this:

var promise = model.save();

$.when(promise).done(function() {
   console.log('success!');
});

$.when(promise).fail(function() {
   console.log('dang');
});

But, $.when() when passed a non-promise fires, done(), so, in the above, if the model is invalid, $.when(false).done() fires, and you get "success!".

I know I can use the success and error attributes in save(), but with my code, it's advantageous to have multiple done() functions applied later. That's the power of the promise afterall.

So, I'm left with:

var promise = model.save();

if (promise) {
    $.when(promise).done(function() {
        console.log('success!');
    });

    $.when(promise).fail(function() {
        console.log('dang');
    });
} else {
    console.log('dang');
}

I hate not being DRY.

var promise = model.save();

var fail = function() {
    console.log('dang');
};

if (promise) {
    $.when(promise).done(function() {
        console.log('success!');
    });

    $.when(promise).fail(function() {
        fail();
    });
} else {
    fail();
}

Geting pretty messy. You get the picture. I'm hoping I'm just missing something here.

like image 723
Matt Avatar asked Sep 20 '13 00:09

Matt


1 Answers

You can override Backbone.save method to have your desired behavior. If the returned value from the original save function is a boolean (which means validation failed), just return a custom promise and reject its related deferred.

var oldSaveFunction = Backbone.Model.prototype.save;
Backbone.Model.prototype.save = function(){
    var returnedValue = oldSaveFunction.apply(this, arguments),
        deferred = new $.Deferred();

    if(_.isBoolean(returnedValue)){
        deferred.reject();
        return deferred.promise();
    }

    return returnedValue;
}

var Person = Backbone.Model.extend({
    url : 'http://www.google.com',
    validate : function(attributes){
         if(!("name" in attributes))
             return "invalid";
    }
});

var person = new Person();
$.when(person.save()).fail(function(){
   console.log("failed"); 
});

Try it on this fiddle

http://jsfiddle.net/WNHXz/1/

like image 104
enriquecastl Avatar answered Sep 30 '22 16:09

enriquecastl