Reputation: 1425
Wondering if any one can help me out here.
I have a single page on the client side running backbone.js
The server is running socket.io.
I have replaced Backbones default sync with the backbone.iobind sync to support socket.io.
I have a backbone model that on save gets an error response from the server (which is planned), and triggers the save's error function, however my model on the client side still updates to the new value. I have included wait:true which from my understanding waits for a success response from the server before updating, however this does not happen for me.
Server side socket.io code
io.sockets.on('connection', function (socket) {
socket.on('test:create', function (data, callback) {
//err - used to fake an error for testing purposes
var err = true;
if (err) {
// error
callback('serv error');
} else {
// success
// The callback accepts two parameters: error and model. If no error has occurred, send null for error.
callback(null, data);
}
});
Client Side Code
//HTML Code
//<div id="callBtns">
//<button id="runTest">Create</button>
//</div>
var CommunicationType = Backbone.Model.extend({
defaults: {
runTest: 'default'
},
urlRoot : '/test',
validate: function(attrs) {
//return 'error';
}
});
var BasicView = Backbone.View.extend({
el: $('#callBtns'),
initialize: function(){
_.bindAll(this);
},
events: {
"click #runTest": "runTestFn"
},
runTestFn: function() {
//causing the issue?
communicationType.set({runTest: 'value from set'});
communicationType.save({},{
success:function(model, serverResponse){
console.log('Success');
console.log(serverResponse);
},
error:function(model, serverResponse){
console.log('Error');
console.log(serverResponse);
console.log(JSON.stringify(communicationType));
},
wait: true
});
}
});
var communicationType = new CommunicationType();
var basicView = new BasicView();
I have noticed that this problem looks to be caused by the fact that I'm using set to update my model directly (communicationType.set({runTest: 'value from set'});)
If I don't set any values before saving, and pass the value in directly to save, like in the code below, it works correctly e.g.
communicationType.save({runTest: 'value from save'},{
success:function(....
However this then means that I can't ever set any new values/update my model without it going via the save function :/
So my question is, how can I get this working correctly (get the client model to not update if there is a server-side error) while still being able to use set?
Any answers are really appreciated! Many Thanks
Upvotes: 1
Views: 497
Reputation: 4479
You may use set
with silent: true
so it won't fire change event.
Upvotes: 0
Reputation: 1097
This can't be done because your model has no way of knowing if it's data is valid until a request is made (model.save in this case).
If you want to prevent Backbone.Model.set from working when you pass invalid values, you must update the model's "validate" function to check for errors.
Given the following validate function:
validate: function(attrs) {
this.errors = [];
if (attrs.runTest === 'wrong_value') {
this.errors.push('error message');
}
return _.any(this.errors) ? this.errors : null;
}
on your CommunicationType model. Running this code in BasicView:
communicationType.set({runTest: 'wrong_value'});
will not change the model.
You can also use the validate function to check for server side errors by returning a errors array and checking for it:
validate: function(attrs) {
this.errors = [];
if (attrs.runTest === 'wrong_value') { // client side check
this.errors.push('error message');
}
if (attrs.errors && attrs.errors.length > 0) { // server side check
for (var key in attrs.errors) {
this.errors.push(attrs.errors[key]);
}
}
return _.any(this.errors) ? this.errors : null;
}
But this will only prevent changing the model when it is saved.
As a hack-ish alternative, you can add server requests inside the validate function that check for errors and prevent the "set" function from changing the model.
Upvotes: 2