1

I'm overriding the fetch method of a Backbone Collection to send a request to a different url in certain circumstances, and I have to send some data with it. The new fetch method (copied from another SO answer) looks like this

fetch(options){

    if(options && options.data){
         options = _.extend({url : '/someendpoint/'}, options || {});
     }

    return Backbone.Collection.prototype.fetch.call(this, options);
}

When I call the fetch method in a view, I pass it some data (that comes in with the options parameter in fetch)

 callFetchMethod(){

   var min = $("#min").val();
   var max = $("#max").val();
   var range = {};
   range['min'] = min;
   range['max'] = max;
   mycollection.fetch({'data': range}); //send the object with min and max to collection
  }

The problem is that the data object is not being recognized on the server. I've tried calling JSON.stringify(range) before sending it to the Collection and also JSON.stringify(options.data) inside the collection, but all to no avail.

I need to use a new url and I need to send data to the server. How can I do it in the fetch method above?

Update: this is what happens in various attempts to stringify the whole options object or just options.data

If I stringify the whole options object like this

if (options && options.data){ options = _.extend({url: '/someendpoint'}, options || {}); options.data = JSON.stringify(options); console.log(options, "options in collection"); }

no data gets sent to the server (and the right url isn’t called)

{"url":"/someendpoint","data":"{\"min\":\"1429740602093\",\"max\":\"1429740602093\"}"}

if I stringify options.data like this

if (options && options.data){
            options = _.extend({url: '/someendpoint'}, options || {});
            options.data = JSON.stringify(options.data);
            console.log(options, "options in collection");
        }

this is out output in the console

Object {url: "/someendpoint", data: "{"min":"1429740602093","max":"1429740602093"}"} "options in collection"

and I get an error on the server that says

the server throws an unexpected end of JSON input error
Leahcim
  • 40,649
  • 59
  • 195
  • 334
  • What about just the options? `JSON.stringify(options)` – colecmc Apr 22 '15 at 22:45
  • @colemc I updated the OP with details about what happens when I stringify options.data and also the whole options object `JSON.stringify(options)` – Leahcim Apr 22 '15 at 22:55
  • is there a way to keep the url and data options distinct using `apply` rather than `call`? – Leahcim Apr 22 '15 at 23:09

1 Answers1

1

So, Backbone.Collection.fetch is calling Collection.sync('read', this, options), where 'read' is the HTTP request method. According to the Docs this translates to an HTTP GET. And we know that according to spec a GET request should ignore all data payloads.

So..., we'll either have to append the range data to the url, or use a POST request instead.

Set your url parameters for fetch

Setting the collection url dynamically is straight forward. In your example, you can do,

callFetchMethod(){
   // assume mycollection already instantiatied
   var min = $("#min").val();
   var max = $("#max").val();
   mycollection.url = '/someendpoint?max=' + max '&min=' + min;
   mycollection.fetch(); // The url is already set
}

Using POST to fetch

Based on this Answer, we can override the POST request on fetch by providing a type property. So, our new callFetchMethod would look like:

callFetchMethod(){
   // assume mycollection already instantiatied
   var min = $("#min").val();
   var max = $("#max").val();
   var range = {};
   range['min'] = min;
   range['max'] = max;
   mycollection.fetch({type: 'POST', data: JSON.stringify(range)});
}

and this should work because what Backbone is doing is:

var xhr = options.xhr = Backbone.ajax(_.extend(params, options));

and while, params has a type property set to GET by Collection.fetch(), _.extend() overwrites that prop with the type property from options, as well as provides the data property to the Backbone.ajax() (which, by the way is nothing but a thin wrapper for $.ajax).

Note:

This code is untested, please let me know if you run into any issues

Community
  • 1
  • 1
seebiscuit
  • 4,905
  • 5
  • 31
  • 47