Trunk Model: Ajax Parsing Request

I have a scenario in which a call to fetch() model will return data from which the property will need to be passed to another API, and the return type from this API will be the actual data required.

 var Issue = Backbone.Model.extend({ urlRoot: 'https://api.github.com/repos/ibrahim-islam/ibrahim-islam.imtqy.com/issues', parse: function(response, options){ var markdown = new Markdown({ text : response.body }); markdown.fetch({ contentType: 'application/json', type: 'POST', data: JSON.stringify( markdown.toJSON() ), success: function(data){ response.body = data; } }); return response; } }); var Markdown = Backbone.Model.extend({ defaults:{ 'text': '', 'mode' : 'markdown' }, url: 'https://api.github.com/markdown' }); 

So, when will the Issue be received:

 var issue = new Issue({id: 1}); issue.fetch().then(function(){ //do stuff }); 

It will have a body property containing syntax markup text, which, in turn, must go to another API and get an answer that will be passed for viewing.

As you can see from the above, I tried to override parse , but its return type should be an object, and fetch would be async , so what can I do here to make this work?

NOTE. I know that aggregating data on a server and then retrieving it would be a better idea, but that is not possible.

+7
javascript jquery ajax backbone-model
source share
2 answers

You can override the synchronization method in your Issue model to link your requests.

 var Issue = Backbone.Model.extend({ urlRoot: 'https://api.github.com/repos/ibrahim-islam/ibrahim-islam.imtqy.com/issues', sync: function(method, model, options) { if (method !== 'read') return Backbone.sync.apply(this, arguments); // first request var xhr = Backbone.ajax({ type: 'GET', dataType: 'json', url: _.result(model, 'url') }); // second request return xhr.then(function (resp1) { var markdown = new Markdown({text : resp1.body || 'body'}); var data = markdown.toJSON(); // the callback to fill your model, will call parse var success = options.success; return Backbone.ajax({ url: _.result(markdown, 'url'), dataType: 'html', contentType: 'application/json', type: 'POST', data: data }).then(function(resp2) { // sets the data you need from the response var resp = _.extend({}, resp1, { body: resp2 }); // fills the model and triggers the sync event success(resp); // transformed value returned by the promise return resp; }); }); } }); 

The parameter hash passed to Model.sync contains callbacks on model.parse , you can use it to set attributes in your model when you are satisfied with your data.

And demo http://jsfiddle.net/puwueqe3/5/

+4
source share

I think you will have to redefine the fetch model to make it work

See what the default selection looks like:

 fetch: function(options) { options = _.extend({parse: true}, options); var model = this; var success = options.success; options.success = function(resp) { var serverAttrs = options.parse ? model.parse(resp, options) : resp; if (!model.set(serverAttrs, options)) return false; if (success) success.call(options.context, model, resp, options); model.trigger('sync', model, resp, options); }; wrapError(this, options); return this.sync('read', this, options); }, 

( github )

This implementation does not support the asynchronous version of model.parse , but since you are creating a model class using .extend , you can override this with your own implementation, so let's see what it does. It takes options objects, creates a success callback, and then passes it to Backbone.Sync .

This is the call that parse calls and what needs to be done to support async.

The quickest and most dirty way to do this is probably to simply copy and modify an existing default selection.

 var MyModel = Backbone.Model.extend({ fetch: function(options) { options = _.extend({parse: true}, options); var model = this; var success = options.success; options.success = function(resp) { function parser(resp, options, cb) { ...do your async request stuff and call cb with the result when done... } parser(resp, options, function(result) { if (!model.set(result, options)) return false; if (success) success.call(options.context, model, resp, options); model.trigger('sync', model, resp, options); }); }; wrapError(this, options); return this.sync('read', this, options); } }); 

This is just an example of how you can solve this. I have not tested it, and it may not work, but I see no obvious reasons why this should not be.

+2
source share

All Articles