Basic save without setting on callback

I have a drag & drop function in my web application. When the user releases the mouse after dragging and moving, the position of the object is saved on the server using the Backbone save () method on the model. When the server responds, it calls set () on the model with the returned properties. However, during the processing of the request by the server, the user could already drag the object to another position. This causes problems, as the response from the server now overrides the settings of the object in the browser.

Is there a way to prevent Backbone from working with set () after receiving a response from the server after saving ()?

+6
source share
10 answers

Now I am using the following solution:

Override the default analysis method for the model:

Backbone.Model.prototype.parse = function(resp, options) { if(options.parse) return resp; }; 

Now you can use the save method with the "parse" parameter set to false to prevent ajax from overriding your current values:

 MyModel.save({}, { parse: false }); 
0
source

Had the same use case when running the system before it had more problems, so we really needed to redefine the set() model functions. Although for this case, several relatively simple methods are available.

You can override the parse () function. Or you can call abort() on the jqXHR object returned by save() .

http://api.jquery.com/jQuery.ajax/#jqXHR

+3
source

Look at the "wait" parameter, by default it should be set to false, which means that your model fields should be set immediately after the save () call. You can set {wait: true} to make the trunk wait for the server to respond before setting updated model field values.

From your described behavior, it looks like in your application the wait parameter is set to true.

Additional information: http://backbonejs.org/#Model-save

Another important thing to remember is the base system, which sets only a subset of the updated fields that you return from the called web service, so if you do not return, no one will be installed.

+2
source

Model.save will call Model.parse for the data received with the same options argument before setting it.

You can invoke Model.save with a special flag (say, position: true ) indicating that Model.parse can cancel what the server returns.

For example, if your x and y coordinates

 var M = Backbone.Model.extend({ parse: function(data, options) { if (options && options.position) data = _.omit(data, 'x', 'y'); return data; } }); var m = new M(); m.save({x: 10, y:10}, {position: true}); m.save({x: 20, y:20}, {position: true}); 

And the demo http://jsfiddle.net/nikoshr/YwC7q/

+2
source

We used an approach to block the user interface until an ajax request was executed. We added two additional events: freezing / thawing of the model, which was run before saving and after receiving a response from the server.

0
source

Try overriding the .sync () method. Backbone.save () delegates to Backbone.sync () after overriding the success callback you are passing to. This is where the model update comes from.

From the source of the Backbone.save () method:

 var success = options.success; options.success = function(resp) { // Ensure attributes are restored during synchronous saves. model.attributes = attributes; var serverAttrs = model.parse(resp, options); if (options.wait) serverAttrs = _.extend(attrs || {}, serverAttrs); if (_.isObject(serverAttrs) && !model.set(serverAttrs, options)) { return false; } if (success) success(model, resp, options); model.trigger('sync', model, resp, options); }; wrapError(this, options); method = this.isNew() ? 'create' : (options.patch ? 'patch' : 'update'); if (method === 'patch') options.attrs = attrs; xhr = this.sync(method, this, options); 

You can pass a custom option when you call ".save ()", then find that option and override the .success callback option to ".sync ()". Something like this, maybe?

 MyModel = Backbone.Model.extend({ sync: function (method, context, options) { if (options.skipUpdateOnResponse) { options.success = myCusomSuccessFunction; } } }); myModel = new MyModel(); myModel.save({...}, {skipUpdateOnResponse: true}) 
0
source

What properties does the server respond to? The default success success callback that Backbone uses does the following:

 if (_.isObject(serverAttrs) && !model.set(serverAttrs, options)) { ... } 

Following this logic, if your server does not return an object, set should not be called on your model.

Alternatively, if you change your server’s response so that it does not return the location information that is being transmitted (which is the main cause of your problem and does not understand your requirements, also seems a bit redundant), these properties shouldn't be overridden when set is called .

Disabling these options, overriding sync , as @Uselessinfo offers or puts some tricks in parse is probably your best best bet.

0
source

Use the model validation method:

 validate: function(attrs) { var errors = []; if (attrs.position !== this.get('position')) { errors.push('Outdated info!'); } return _.any(errors) ? errors : null; } 

Thus, you can compare the server response with existing data in the model. If the server response is different from the data in the model, return errors and the set method will not be called. This may require wait: true in the parameters of the save method. With this approach, I think you should set the position on the model before doing the actual save.

validate is called before saving, but can also be called before setting if {validate: true}

0
source

Return to the opposite side:

  options.success = function(resp, status, xhr) { done = true; var serverAttrs = model.parse(resp, xhr); if (options.wait) serverAttrs = _.extend(attrs || {}, serverAttrs); if (!model.set(serverAttrs, options)) return false; if (success) success(model, resp, options); model.trigger('sync', model, resp, options); }; 

Thus, it calls set allways before the "sync" call, and before the user function call. There is no way to prevent the creation of a core network, but there is a way to solve your problem. You can override the "set" function in your model as follows:

 set: function() { if (this.skipSetOperation()) return false; return Backbone.Model.prototype.set.apply(this, arguments); }, skipSetOperation: function() { //this function should return stage - can model set attributes in this moment or not } 

Hope this helps.

0
source

Write another function to save, and use your function instead of saving.

in model:

 var myModel = Backbone.Model.extend({ savePosition: function(){ var model = this; $.ajax({ type : "POST", cache: false, dataType : 'json', contentType : 'application/json', data:JSON.stringify(data), url : "urlToSave", success:function(responseText,statusText){ model.trigger('saved',responseText); }, error : function(error, dataObj, xhr) { alert('Error'); } }); } } 

here, by sight, the binding method is saved and starts the method after saving.

 this.model.on('saved',function(){ // do call back stuff }); this.model.savePosition({data:{...}}); 
-1
source

Source: https://habr.com/ru/post/952224/


All Articles