web-dev-qa-db-de.com

Backbone.js Model unterschiedliche URL zum Erstellen und Aktualisieren?

nehmen wir an, ich habe ein Backbone-Modell und erstelle eine Instanz eines Modells wie das folgende:

var User = Backbone.Model.extend({ ... });
var John = new User({ name : 'John', age : 33 });

Ich frage mich, ob es möglich ist, wenn ich John.save() zum Zielen auf /user/create verwende, wenn ich John.save() zum zweiten Mal (update/PUT) zum Zielen auf /user/update verwende, wenn ich John.fetch() zum Zielen auf /user/get verwende und wenn ich John.remove() zum Zielen auf /user/remove verwende.

Ich weiß, dass ich jedes Mal John.url definieren kann, bevor ich eine Methode auslöse, aber ich frage mich, ob dies automatisch passieren kann, ohne eine Backbone-Methode zu überschreiben.

Ich weiß, dass ich eine URL wie /user/handle verwenden und die Anfrage basierend auf der Anfragemethode (GET/POST/PUT/DELETE) bearbeiten könnte, aber ich frage mich nur, ob es eine Möglichkeit gibt, eine andere URL pro Aktion in Backbone zu haben.

Vielen Dank!

31
panosru

Die Methoden .fetch() , .save() und .destroy() on Backbone.Model prüfen, ob das Modell .sync() definiert ist, und wenn ja, wird es aufgerufen, andernfalls wird Backbone.sync() aufgerufen (siehe letzte Zeilen des verknüpften Quellcodes) ).

Eine der Lösungen ist also die Implementierung der .sync()-Methode.

Beispiel:

var User = Backbone.Model.extend({

  // ...

  methodToURL: {
    'read': '/user/get',
    'create': '/user/create',
    'update': '/user/update',
    'delete': '/user/remove'
  },

  sync: function(method, model, options) {
    options = options || {};
    options.url = model.methodToURL[method.toLowerCase()];

    return Backbone.sync.apply(this, arguments);
  }
}
78
kubetz

Um dzejkejs solution eine Ebene weiter zu abstrahieren, können Sie die Backbone.sync - Funktion einschließen, um das Modell nach methodenspezifischen URLs abzufragen.

function setDefaultUrlOptionByMethod(syncFunc)
    return function sync (method, model, options) {
        options = options  || {};
        if (!options.url)
            options.url = _.result(model, method + 'Url'); // Let Backbone.sync handle model.url fallback value
        return syncFunc.call(this, method, model, options);
    }
}

Dann könnten Sie das Modell definieren mit:

var User = Backbone.Model.extend({
    sync: setDefaultUrlOptionByMethod(Backbone.sync),
    readUrl: '/user/get',
    createUrl: '/user/create',
    updateUrl: '/user/update',
    deleteUrl: '/user/delete'
});
2
Michael Kropat

Behandeln Sie eine REST -Implementierung, die nicht spezifiziert ist oder eine Art Problemumgehung erfordert?

Verwenden Sie stattdessen die emulateHTTP-Option, die Sie hier finden:

http://documentcloud.github.com/backbone/#Sync

Andernfalls müssen Sie wahrscheinlich nur die standardmäßige Backbone.sync-Methode überschreiben, und Sie sind gut aufgestellt, wenn Sie wirklich verrückt werden möchten ... aber ich schlage das nicht vor. Am besten verwenden Sie einfach eine echte RESTful-Schnittstelle.

1
dlamotte

Nein, mit Backbone ist dies standardmäßig nicht möglich. Was Sie tun können, ist dem Modell hinzuzufügen, das die Modell-URL bei jedem Ereignis ändert, das der Modell-Trigger auslöst. Aber dann haben Sie immer das Problem, dass bckbone POST verwendet, wenn das Modell zum ersten Mal gespeichert wurde, und PUT für jeden Aufruf danach. Daher müssen Sie auch die save()-Methode oder Backbone.sync überschreiben. 

Schließlich scheint es keine gute Idee zu sein, da dies das REST-Muster bricht, auf dem Backbone aufgebaut ist.

0

Ich wurde von this solution inspiriert, bei der Sie einfach Ihren eigenen Ajax-Aufruf für die Methoden erstellen, die nicht zum Abrufen des Modells dienen. Hier ist eine abgespeckte Version davon:

var Backbone = require("backbone");
var $ = require("jquery");
var _ = require("underscore");

function _request(url, method, data, callback) {
  $.ajax({
    url: url,
    contentType: "application/json",
    dataType: "json",
    type: method,
    data:  JSON.stringify( data ),
    success: function (response) {
      if ( !response.error ) {
        if ( callback && _.isFunction(callback.success) ) {
          callback.success(response);
        }
      } else {
        if ( callback && _.isFunction(callback.error) ) {
          callback.error(response);
        }
      }
    },
    error: function(mod, response){
      if ( callback && _.isFunction(callback.error) ) {
        callback.error(response);
      }
    }
  });
}

var User = Backbone.Model.extend({

  initialize: function() {
    _.bindAll(this, "login", "logout", "signup");
  },

  login: function (data, callback) {
    _request("api/auth/login", "POST", data, callback);
  },

  logout: function (callback) {
    if (this.isLoggedIn()) {
      _request("api/auth/logout", "GET", null, callback);
    }
  },

  signup: function (data, callback) {
    _request(url, "POST", data, callback);
  },

  url: "api/auth/user"

});

module.exports = User;

Und dann kannst du es so benutzen:

var user = new User();

// user signup
user.signup(data, {
  success: function (response) {
    // signup success
  }
});

// user login
user.login(data, {
  success: function (response) {
    // login success
  }
});

// user logout
user.login({
  success: function (response) {
    // logout success
  }
});

// fetch user details
user.fetch({
  success: function () {
    // logged in, go to home
    window.location.hash = "";
  },
  error: function () {
    // logged out, go to signin
    window.location.hash = "signin";
  }
});
0
mlunoe