I can only tell from my experience and this is obviously going to be very opinionated.
I don't like to actually set values on a model without asking the server first whether a value change is valid enough to get committed and therefore broadcast to all modules eventually displaying or depending on the model object in question. It is very much possible that an input is not going to be accepted by the server even though it passed all the conditions the client was able to check against (e.g. valid email, but not unique on the server).
That being said, some of the input should and can be immediately validated without asking the backend first. In the end, it's probably going to be a "best of both worlds". Shitty wisdom, I know ;).
The most important thing here is the ability to roll back to a previous valid state, no matter what part of the process caused the invalidation. I'm referring to this weird outdated/updated state you mentioned above. We only can absolutely be sure about the correctness of a change if "computer says yes" (backend, that is).
Now, how to achieve that? Here's two approaches (prerequisite for both examples: all model objects have a unique ID attribute and if not we're talking "create"):
Modify a temporary object, mirror to actual object if it validates.
Let the form represent a new model object, no matter whether we're talking "update" or "create". You're perfectly able to distinguish between the two by asking for the ID later on:
// update
var tempModel = new MyModel(modelToUpdate.serialize());
// or create
var tempModel = new MyModel();
set
and / or submit
the object values depending on the user experience you want to provide. I would have the validation process as general as possible and always validating the object (each and every key/value pair) as a whole. More on that a little later.
In case of a valid (and complete) modification process, mirror the changes back to your actual model object or create a new one:
var model;
if (tempModel.isValid() === false) {
// report Error
} else if (tempModel.get('id')) {
model = modelToUpdate.set(tempModel.serialize()).save();
} else {
model = tempModel.save();
// do what you got to do with a new model object
}
Major cons: As long as you don't track the temporarily created model object, other parts of the app won't be aware of the upcoming changes.
Keep current state in a temporary object, roll back to its state if validation fails.
Save the current and hopefully valid state of the model object before modification process starts to take place:
var currentlyValid = new MyModel(modelToUpdate.serialize());
set
and / or submit
the actual object as you see fit. You should again not care to much about specific key/value pairs but make sure that the whole object is valid, The main advantage here is that other parts of the app depending on and / or displaying the object in question, will stay in sync. Main disadvantage: You got to handle the creation of new items separately.
Get lost of the temporary object if modifications got validated. If not, roll back to the previously saved state.
if (modelToUpdate.isValid()) {
var currentlyValid = null;
modelToUpdate.save();
} else {
modelToUpdate.set(currentlyValid.serialize());
}
Major con: I can't think of a streamlined way of creating new objects with this approach. Depends on implementation, I guess.
I for one prefer the first approach. If it is all about syncing other parts of your app that are supposed to display the changes on a model object with the current temp object on blur, one could establish an application model object that has a property which points at the latter and triggers change events whenever the temporary object gets modified:
var app = MyApplication({
modelThatIsGettingModified: <Reference to the temp object>;
});
Because every set
call that passed client-side validation will modify the return of this model property, no matter whether the whole object got confirmed by the server or not.
A word about validation
Given the fact that the validation method on Backbone models ...
... is left undefined, and you're encouraged to override it
with your custom validation logic, if you have any that can be
performed in JavaScript ... (source Backbone docs)
... I'd suggest you always validate against all key/value pairs. May cause some overhead, that's for sure, but this will let you unify validation process. I'm very much aware of 1, 2 and 3, but let's be honest, these kind of things will hardly slow down your app as long as you keep the DOM in check. Having a streamlined validation process is much more important here. If these kind of redundancies start to have an impact on the performance of your thing, you probably shouldn't be using Backbone at all IMHO.