web-dev-qa-db-fra.com

Backbone.js Modéliser des URL différentes pour créer et mettre à jour?

disons que j'ai un modèle Backbone et que je crée une instance d'un modèle comme celui-ci:

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

Je me demande s'il est possible lorsque j'utilise John.save() de cibler /user/create lorsque j'utilise John.save() une deuxième fois (update/PUT) sur /user/update cible lorsque j'utilise John.fetch() pour cibler /user/get et lorsque j'utilise John.remove() pour cibler /user/remove

Je sais que je pourrais définir John.url chaque fois avant de déclencher une méthode, mais je me demande si cela pourrait se produire automatiquement sans modifier la méthode Backbone.

Je sais que je pourrais utiliser une URL telle que /user/handle et gérer la requête en fonction de la méthode de requête (GET/POST/PUT/DELETE), mais je me demande s’il existe un moyen d’avoir une URL différente par action dans Backbone.

Merci!

31
panosru

Méthodes .fetch() , .save() et .destroy() on Backbone.Model vérifie si le modèle a défini .sync() et si oui, il sera appelé sinon Backbone.sync() sera appelé (voir les dernières lignes du code source lié ).

Une des solutions consiste donc à implémenter la méthode .sync().

Exemple:

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

Pour résumer dzejkej} solution d'un niveau, vous pouvez envelopper la fonction Backbone.sync pour interroger le modèle sur URL spécifiques à une méthode.

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);
    }
}

Ensuite, vous pouvez définir le modèle avec:

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

Avez-vous affaire à une implémentation REST non spécifiée ou nécessitant une solution de contournement?

Pensez plutôt à utiliser l'option emulateHTTP trouvée ici:

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

Sinon, vous devrez probablement simplement remplacer la méthode par défaut Backbone.sync et vous pourrez continuer si vous voulez devenir vraiment fou avec ça ... mais je ne le suggère pas. Il serait préférable d'utiliser simplement une véritable interface RESTful.

1
dlamotte

Non, vous ne pouvez pas faire cela par défaut avec le réseau fédérateur. Ce que vous pouvez faire est d’ajouter au modèle qui modifiera l’URL du modèle à chaque événement déclenché par le modèle. Mais vous avez toujours le problème que bckbone utilisera POST ajouter la première fois que le modèle a été enregistré et PUT pour chaque appel suivant. Vous devez donc également remplacer la méthode save() ou Backbone.sync

Après tout, il semble que ce ne soit pas une bonne idée de le faire, car cela brise le modèle REST sur lequel Backbone est construit.

0
Andreas Köberle

Je me suis inspiré de this solution, où vous créez simplement votre propre appel ajax pour les méthodes qui ne permettent pas d’extraire le modèle. En voici une version allégée:

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;

Et ensuite, vous pouvez l'utiliser comme ceci:

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