Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Encoding JSON to URL params for Backbone.Model.save (patch = true)

I'm having some trouble correctly forming a Backbone.Model.save call. The web service I'm calling consumes URL parameters, but what I have in Javascript is an object of changed fields. For example, I have the object {foo: 'bar', yar: 'har'}, and I want Backbone.Model.save to send a patch request to a URL like http://server/path/to/service?foo=bar&yar=har

Sounds simple, right? It's giving me a bunch of trouble anyway. Here's what I've got so far (which doesn't work; I have success/error callbacks, too, but I don't think those are important for the question):

object = 
    foo: 'bar', 
    yar: 'har'

model.save object,
    patch: true

I've tried some other options, too:

model.save object,
    patch: true
    emulateJSON: true

This set contentType to "application/x-www-form-urlencoded", which is good, but the data sent in the ajax request by Backbone.sync was: {model: "{"foo": "bar", "yar": "har"}". The service got that and has no idea what to do with a "model" property.

model.save object,
    patch: true
    contentType: "application/x-www-form-urlencoded"

This just codes object as a string and stuffs that into options.data. Again, the service doesn't know what to do with it.

Any other ideas on how I can get this to conform to my service's spec? I can make the ajax call myself and update the model (and the collection it belongs to) myself, but I'd really rather not do that. An ajax request that works for me is:

$.ajax
    url: "http://server/path/to/service"
    type: "PATCH"
    data: object

Update: The reason my two earlier options didn't work is clear in Backbone.js itself:

// Ensure that we have the appropriate request data.
if (options.data == null && model && (method === 'create' || method === 'update' || method === 'patch')) {
  params.contentType = 'application/json';
  params.data = JSON.stringify(options.attrs || model.toJSON(options));
}

// For older servers, emulate JSON by encoding the request into an HTML-form.
if (options.emulateJSON) {
  params.contentType = 'application/x-www-form-urlencoded';
  params.data = params.data ? {model: params.data} : {};
}

Looking at this, I thought maybe if I stuffed the object into object into options.data and sent in empty attributes, perhaps it'd work:

model.save {},
    patch: true
    data: object

Apparently this tried to PATCH an option "[object Object]". I guess it did a stringify of the object... somewhere... but this may be close to the right answer?

like image 301
Depressio Avatar asked Nov 03 '22 06:11

Depressio


1 Answers

It looks like what I was looking for is the processData option to jQuery.ajax. Backbone.sync does the following by default:

// Don't process data on a non-GET request.
if (params.type !== 'GET' && !options.emulateJSON) {
  params.processData = false;
}

Thus, it wasn't processing the object into URL parameters for me. (jQuery API)

So, a working bit of code would be:

model.save {},
    patch: true
    data: object
    processData: true

In truth, I may not be using Backbone.Model correctly overall... but, at least it's working. :P

like image 160
Depressio Avatar answered Nov 09 '22 06:11

Depressio