简体   繁体   中英

Prevent Backbone set validates after save

I'm trying to do client side validation on a Backbone model that involves an ajax call to the server in order to determine if the new entry is a duplicate of an existing one (determined by matching a title). Here's the steps

  1. Check if model is new.
  2. If new, AJAX GET from validate() to see if model exists already (by title).
  3. If response = duplicate set status invalid, if not proceed with save()

The problem Im having is that Backbone is doing the following.

  1. save()
  2. validate() : GET returns not duplicate
  3. validation passed, set()
  4. validate() : GET returns duplicate

My question is about how to prevent that second validate() from firing on the set because it triggers another GET request and I get an error response even though technically Im "done" saving.

To keep this short here is the validate, and save calls

List = Backbone.Model.extend({

idAttribute: "_id",

urlRoot: '/api/lists',
...

validate: function(attrs) {
    // if we are editing don't bother with this (for now)
    if (this.isNew()) {

        // see if this title already exists
        var result = '';

        $.ajax({
            url: "/api/lists/" + this.generateTitleKey(attrs.title),
            type: "GET",
            async: false,
            success: function(data){
                result = data;
            }
        });

        if(result.length > 0) {
                return {
                    field: "title",
                    errMsg: "You already have this list"
                };
        }
    }
}
});


ListView = Backbone.View.extend({

...

save: function() {

    var _self = this;
    var fields = {
        title: _self.$el.find('input[name="new-list-name"]').val()
    }

    _self.resetErrors();

    _self.model.save(fields, {
        wait: true,
        silent: true,
        success: function(model, res) {
            if(res.err) {
                // add UI error
            } else {
                new app.View({ model: _self.model });
                _self.close();
            }
        },
        error: function(model, res) {
            console.log('inside error');
        }
    })
}
});

app.post('/api/lists', function(req, res){

var list = new ListModel({
    titleKey: generateTitleKey(req.body.title),
    title: req.body.title
});

return list.save(function(err){
    if(!err) {
        return res.send(list);
    } else {
        return res.status(409).send(JSON.stringify({
            err: true,
            errSrc: "list",
            errType: "insert",
            errMsg: "That's already a list!"
        }));
    }
});
});

silent: true doesnt seem to be working for me, save() and set() both trigger validate().

I know there are a number of approaches to doing error handling for validation but I'm purposely trying to use the native valide method that a backbone Model has, and its been working great UNTIL I try to use it with the ajax call. Im so close here I can taste it.

You can tell the model not to validate a set with model.set('something', true, { validate: false }); . FYI you can do the same in the .save options hash if you need to.

What are you setting anyway? Normally the server response is the attributes you want to save on the client model so maybe you can return what you need on that and avoid calling set.

Dominic Tobias led me to the right answer.

isNew() wont work as a check because on the response from the server, the model is validated BEFORE it's set, so isNew() is still technically true at the time of validation for the post save() set. I changed the check in validate() to if(attrs._id) and everything works.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM