8

I'm attempting to build out a simple TODO plugin using Backbone and have run into an issue with the AJAX API. In order to get the correct AJAX call back you have to pass in the "action" parameter like this:

admin-ajax.php?action=get_todos

which works fine for the GET method in Backbone. However, when using DELETE Backbone will use a URL like this by default:

admin-ajax.php?action=get_todos/9

where "9" is the ID of the todo being deleted. By adding on this ID it breaks the AJAX call on the WordPress side. I can manually override the URLs for each of the methods but I'd like to know if there's a more elegant way to get the AJAX API to work with Backbone.

I've created a demo plugin which shows the specific issue I've run in to. Load the settings page and click on any of the X's while watching your Network inspector to see the 0 value AJAX results coming from WordPress.

https://github.com/hereswhatidid/wordpress-todo-backbone-demo

2
  • +1 as I find the topic interesting, but please add the specific/relevant/not working parts of your code to the question.
    – kaiser
    Oct 30, 2013 at 18:20
  • I tried this before and so far haven't got it working. Instead I used the WordPres Rewrite API rules to get the post id. Note that I only use it to get an archive (post type archive or term )as collection and a single (post or custom post type) as a model.
    – ifdion
    Nov 23, 2013 at 0:32

2 Answers 2

2

You need to override the Backbone.sync function to change the URL used for the AJAX call. You can learn from the plugin wp-backbone does this and more. Below you can see from it how it changes all the actions into either POST or GET, create the parameters, add the action parameter and more.

(function($) {
Backbone.sync = function(method, model, options) {

    var params = _.extend({
        type:         'POST',
        dataType:     'json',
        url: wpBackboneGlobals.ajaxurl,
        contentType: 'application/x-www-form-urlencoded;charset=UTF-8'
    }, options);

    if (method == 'read') {
        params.type = 'GET';
        params.data = model.id
    }

    if (!params.data && model && (method == 'create' || method == 'update' || method == 'delete')) {
        params.data = JSON.stringify(model.toJSON());
    }


    if (params.type !== 'GET') {
        params.processData = false;
    }

    params.data = $.param({action:'backbone',backbone_method:method,backbone_model:model.dbModel,content:params.data});

    // Make the request.
    return $.ajax(params);


};

})(jQuery);
2

You don't need to override Backbone.sync since Backbone.sync will override its own $.ajax request with the parameters you pass as options. See this link for a walkthrough of how Backbone.sync works internally: http://backbonejs.org/docs/backbone.html#section-141

You can add something like the following in your model or collection:

save: function(){
    var $params = {
        emulateJSON: true, 
        data: { 
                 action: 'your_wp_ajax_action', 
                 payload : this.toJSON() 
              } 
        };

    //return $.post(this.url, $params, null);

    return Backbone.sync( 'create', this, $params );
}

And then process the data as regular post data on the server side (with your model/models in $_POST['payload']).

This method does:

  • create an array of the necessary overrides for the ajax call.
  • turn on 'classic POST' with the emulateJSON param: it makes for a leaner syntax on both the frontend and backend. You would have to use JSON.stringify on the 'data' param otherwise.
  • return the result of a call to Backbone.sync, with a default configuration of 'create' (POST), a dataset of {model} or {models} if a collection, and our own overrides.

$_POST['payload'] then contains an array of all your Backbone data.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.