backbone.js use different urls for model save and fetch

46,520

Solution 1

If you're reading the source you probably already have a working solution. You essentially have two options (probably more)-

  1. Pass URL in save()/fetch()

save() takes two parameters attr and options attr - is a hash of model attributes and is used to update the model before save. eg.

myModel.save(attrs)

is equivalent to

myModel.set(attrs)
myModel.save()

The second parameter is an options hash, which is passed down to this.sync() (and then Backbone.sync and then $.ajax) - setting the url in this hash will work as expected. You can pass false, undefined, or {} as the first parameter to skip the update.

  1. Override Backbone.sync

Rather than have url's scattered throughout your code every time you call save() or fetch() write your own sync function to compute the url for you, the delegate to the original Backbone.sync to do the heavy lifting

eg. (This sync function adds /save to the url on CREATE, UPDATE and DELETE actions)

function mySyncFunction(method, model, options){
  if(method=='GET'){
    options.url = model.url; 
  }else{
     options.url = model.url + '/save'; 
  }
  return Backbone.sync(method, model, options);
}

To use your custom sync method just declare it as part of your model

var myModel = Backbone.Model.extend({ 
  ...

  "sync": mySyncFunction,

  ...
});

Solution 2

Gingerhendrix's answer covers the bases, but I thought it was worth elaborating on the method for passing in an options value for save/delete/fetch.

Instead of littering your code with urls every place you call one of those methods, you can also override the method on your model than then delegate back to the original Backbone.Model method like this:

var MyModel = Backbone.Model.extend({
  save: function(attributes, options) {
    options = _.defaults((options || {}), {url: "http://your.save.url.com/"});
    return Backbone.Model.prototype.save.call(this, attributes, options);
  },
  // same thing for fetch and delete to give them different urls...
}

Then, you can call the method in your code without having to worry about remembering to set the url in the options.

Solution 3

I want to clearify answer of @gingerhendrix: you can pass url to to options in save and it will go directly to xhr request (it is not obvious from documentation or source code or from answer so I post ot as separate answer):

model.save({}, {url: '/custom-url'});

Solution 4

If you have a model and a collection like :-

MyModel = Backbone.Model.extend({

url: function(){ "API/"
      return "API/MyModel/" +this.get("id");
    }
});

MyCollection = Backbone.Collection.extend({
    model: MyModel ,
    url: "API/MyModels"
});

to fetch the collection just call

MyCollection.fetch({
       success: function(){
       //do something here
       },
       error: function(){
       //Handle your error
       }
});

To save your model assuming you have the id of the model and you have instantiated your collection (calling it myCollection).

var model = myCollection .get(id);
   model.save(
                             model.attributes,
                                {
                                    success: function (model, response) {

                                        //do something on success
                                    },
                                    error: function (model, response) {
                                       //handle the error
                                    }
                                }
                            );
Share:
46,520
fortuneRice
Author by

fortuneRice

Updated on September 15, 2020

Comments

  • fortuneRice
    fortuneRice over 3 years

    My back-end has two separate pages, one for handling the model save request and the other for model fetch.

    What is the best approach for calling save() and fetch() to use different URLs? Thanks.

    Edit: After studying the annotated source, I see that one can actually supply an options hash to fetch and save

    //taken from backbone source:
    save : function(attrs, options) {
      options || (options = {});
      if (attrs && !this.set(attrs, options)) return false;
      var model = this;
      var success = options.success;
      options.success = function(resp, status, xhr) {
        if (!model.set(model.parse(resp, xhr), options)) return false;
        if (success) success(model, resp, xhr);
      };
      options.error = wrapError(options.error, model, options);
      var method = this.isNew() ? 'create' : 'update';
      return (this.sync || Backbone.sync).call(this, method, this, options);
    },
    

    In the save, what purpose does the attrs serve? I've just been calling myModel.save() without passing anything in and it's always been hashing my model's attributes correctly. But now that I want to supply a 'save url' and I'm tempted to call

    myModel.save(undefined, {
        url: 'myPath'
    })
    

    with the undefined required to 'skip' the first attrs paramter.

  • nrabinowitz
    nrabinowitz over 12 years
    It doesn't seem like this answer addresses the OP's actual problem at all - s/he needs to .save() to a different URL than the .fetch() URL.
  • nrabinowitz
    nrabinowitz over 12 years
    Nice clear answer. Overriding the default sync method is definitely the better option here.
  • Jason Stonebraker
    Jason Stonebraker over 11 years
    FYI... When using .fetch() the method value appears to be "read".
  • mnoble01
    mnoble01 about 11 years
    As of Backbone 0.9.10: var methodMap = { 'create': 'POST', 'update': 'PUT', 'patch': 'PATCH', 'delete': 'DELETE', 'read': 'GET' };
  • Jackie Chan
    Jackie Chan over 10 years
    Uncaught TypeError: Property 'sync' of object [object Object] is not a function
  • Deniz Ozger
    Deniz Ozger over 9 years
    What do we need to pass as attributes - can you provide a complete usage example?
  • Robert
    Robert over 7 years
    I have tried this with no luck. I get "Error: a url property or function must be specified". Would be great if that did work.
  • Leonid Shagabutdinov
    Leonid Shagabutdinov over 7 years
    jsbin.com/tawidaruma/edit?html,js,output, proofscreen: i.imgur.com/xc8Jtyg.png; please, show your code so I can say what going on.
  • Not a machine
    Not a machine almost 7 years
    @gingerhendrix It is better to override the default sync method when you have read-only data that you will never need to save nor update? I like your answer and want to keep my code as efficient as possible.