"Cómo" guardar una colección completa en Backbone.js-Backbone.sincronización o jQuery.ajax?


Soy muy consciente de que se puede hacer y he mirado varios lugares (incluyendo: ¿Las mejores prácticas para guardar una colección completa?). Pero todavía no estoy claro "exactamente cómo" está escrito en código? (el post lo explica en inglés. Sería genial tener una explicación específica de javascript:)

Digamos que tengo una colección de modelos - los modelos mismos pueden tener colecciones anidadas. He anulado el método toJSON() de la colección padre y estoy obteniendo un JSON válido objeto. Deseo "guardar" toda la colección (correspondiente JSON), pero backbone no parece venir incorporado con esa funcionalidad.

var MyCollection = Backbone.Collection.extend({
model:MyModel,

//something to save?
save: function() {
   //what to write here?
 }

});

Sé que en algún lugar tienes que decir:

Backbone.sync = function(method, model, options){
/*
 * What goes in here?? If at all anything needs to be done?
 * Where to declare this in the program? And how is it called?
 */
}

Una vez que la 'vista' ha terminado con el procesamiento, es responsable de decirle a la colección que se "guarde" en el servidor (capaz de manejar una solicitud de actualización/creación masiva).

Preguntas que surgen:

  1. Cómo / qué escribir en código para " cablear todo juntos"?
  2. ¿Cuál es la ubicación 'correcta' de las devoluciones de llamada y cómo especificar una devolución de llamada "éxito/error"? Quiero decir sintácticamente?No estoy claro de la sintaxis de registro de callbacks en backbone...

Si realmente es un trabajo complicado, podemos llamar a jQuery.ajax dentro de una vista y pasar el this.successMethod o this.errorMethod como devoluciones de llamada de éxito/error?? ¿Funcionará?

Necesito estar en sincronía con la forma de pensar de backbone - Sé que definitivamente me estoy perdiendo algo w. r. t., la sincronización de todo colecciones.

Author: Community, 2011-07-30

11 answers

Mi pensamiento inmediato no es anular el método en guardar método en Backbone.Pero envuelva la colección en otra columna vertebral.Modele y anule el método toJSON en eso. Luego La columna vertebral.js tratará el modelo como un único recurso y no tienes que hackear la forma en que backone piensa demasiado.

Tenga en cuenta que la columna vertebral.Colección tiene un método toJSON por lo que la mayor parte de su trabajo está hecho para usted. Solo tienes que proxy el método toJSON de tu Backbone wrapper.Modelo a la Vertebral.colección.

var MyCollectionWrapper = Backbone.Model.extend({
url: "/bulkupload",

//something to save?
toJSON: function() {
    return this.model.toJSON(); // where model is the collection class YOU defined above
 }

});
 64
Author: bradgonesurfing,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-07-30 20:35:40

Un muy simple...

Backbone.Collection.prototype.save = function (options) {
    Backbone.sync("create", this, options);
};

...le dará a sus colecciones un método de guardado. Tenga en cuenta que esto siempre publicará todos los modelos de la colección en el servidor, independientemente de lo que haya cambiado. las opciones son solo opciones normales de jQuery ajax.

 25
Author: hacklikecrack,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-04-14 22:17:22

Terminé teniendo un método 'save' like y llamé $.ajax dentro de él. Me dio más control sobre él sin la necesidad de agregar una clase de envoltura como sugirió @brandgonesurfing (aunque me encanta la idea :) Como se mencionó ya que ya tenía la colección.El método toJSON () sobrescrito todo lo que hice fue usarlo en la llamada ajax...

Espero que esto ayude a alguien que tropieza con él...

 8
Author: PhD,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-01-14 15:53:36

Esto realmente depende de cuál sea el contrato entre el cliente y el servidor. Aquí hay un ejemplo simplificado de CoffeeScript donde un PUT a /parent/:parent_id/children con {"children":[{child1},{child2}]} reemplazará a los hijos de un padre con lo que está en el PUT y devolverá {"children":[{child1},{child2}]}:

class ChildElementCollection extends Backbone.Collection
  model: Backbone.Model
  initialize: ->
    @bind 'add', (model) -> model.set('parent_id', @parent.id)

  url: -> "#{@parent.url()}/children" # let's say that @parent.url() == '/parent/1'
  save: ->
    response = Backbone.sync('update', @, url: @url(), contentType: 'application/json', data: JSON.stringify(children: @toJSON()))
    response.done (models) => @reset models.children
    return response

Este es un ejemplo bastante simple, puedes hacer mucho más... realmente depende de en qué estado están tus datos cuando se ejecuta save (), en qué estado deben estar para enviarlos al servidor y qué devuelve el servidor.

Si su servidor está bien con un PUESTO de [{child1},{child2], entonces su columna vertebral.la línea de sincronización podría cambiar a response = Backbone.sync('update', @toJSON(), url: @url(), contentType: 'application/json').

 5
Author: carpeliam,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-03-25 22:20:31

La respuesta depende de lo que quieras hacer con la colección en el lado del servidor.

Si tiene que enviar datos adicionales con el post, es posible que necesite un modelo de envoltura o un modelo relacional.

Con el modelo wrapper siempre tienes que escribir tu propio método parse :

var Occupants = Backbone.Collection.extend({
    model: Person
});

var House = Backbone.Model.extend({
    url: function (){
        return "/house/"+this.id;
    },
    parse: function(response){
        response.occupants = new Occupants(response.occupants)
        return response;
    }
});

Modelos relacionales son mejores creo, porque se puede configurarlos más fácil y se puede regular con el Incluidoenjson opción que atributos poner en el json que envía a su servicio rest.

var House = Backbone.RelationalModel.extend({
    url: function (){
        return "/house/"+this.id;
    },
    relations: [
        {
            type: Backbone.HasMany,
            key: 'occupants',
            relatedModel: Person,
            includeInJSON: ["id"],
            reverseRelation: {
                key: 'livesIn'
            }
        }
    ]
});

Si no envía datos adicionales , puede sincronizar la colección en sí. Tienes que añadir un método save a tu colección (o al prototipo de colección) en ese caso:

var Occupants = Backbone.Collection.extend({
    url: "/concrete-house/occupants",
    model: Person,
    save: function (options) {
        this.sync("update", this, options);
    }
});
 5
Author: inf3rno,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-05-31 15:44:01

También me sorprendió que las colecciones de Backbone no tengan un guardado incorporado. Esto es lo que puse en mi colección de columna vertebral para hacerlo. Definitivamente no quiero iterar a través de cada modelo de la colección y guardar de forma independiente. Además, estoy usando Backbone en el backend usando Node, por lo que estoy sobrescribiendo el nativo Backbone.sync para guardar en un archivo plano en mi pequeño proyecto,pero el código debería ser más o menos el mismo:

    save: function(){                                                                                                                                                                                                                                                                                                                                                     
      Backbone.sync('save', this, {                                                                                                                                                                                                                                                                                                                                     
        success: function(){                                                                                                                                                                                                                                                                                                                                          
          console.log('users saved!');                                                                                                                                                                                                                                                                                                                              
        }                                                                                                                                                                                                                                                                                                                                                             
      });                                                                                                                                                                                                                                                                                                                                                               
    }
 3
Author: Mauvis Ledford,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-10-18 18:33:26

Viejo hilo que sé, lo que terminé haciendo es lo siguiente:

Backbone.Collection.prototype.save = function (options) {
            // create a tmp collection, with the changed models, and the url
            var tmpCollection = new Backbone.Collection( this.changed() );
            tmpCollection.url = this.url;
            // sync
            Backbone.sync("create", tmpCollection, options);
        };
        Backbone.Collection.prototype.changed = function (options) {
            // return only the changed models.
            return this.models.filter( function(m){
                return m.hasChanged()
            });
        };
// and sync the diffs.
self.userCollection.save();

Bastante tensa hacia delante:)

 3
Author: Rene Weteling,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-12-24 08:44:26

Este es un ejemplo sencillo:

var Books = Backbone.Collection.extend({
model: Book,
url: function() {
  return '/books/';
},
save: function(){
  Backbone.sync('create', this, {
    success: function() {
      console.log('Saved!');
    }
  });
 }
});

Cuando llamas al método save() en tu colección, enviará una solicitud de método PUT a la URL definida.

 2
Author: Gaurav Gupta,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-03-12 12:55:48

Intentaría algo como:

var CollectionSync = function(method, model, [options]) {
    // do similar things to Backbone.sync
}

var MyCollection = Backbone.Collection.extend({
    sync: CollectionSync,
    model: MyModel,
    getChanged: function() {
        // return a list of models that have changed by checking hasChanged()
    },
    save: function(attributes, options) {
        // do similar things as Model.save
    }
});

( https://stackoverflow.com/a/11085198/137067 )

 1
Author: philfreo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:09:09

La respuesta aceptada es bastante buena, pero puedo ir un paso más allá y darle código que asegurará que los eventos adecuados se disparen para sus oyentes mientras que también le permite pasar la opción ajax event callbacks:

save: function( options ) {
  var self = this;

  var success = options.success;
  var error = options.error;
  var complete = options.complete;

  options.success = function( response, status, xhr ) {
    self.trigger('sync', self, response, options);
    if (success) return success.apply(this, arguments);
  };

  options.error = function( response, status, xhr ) {
    self.trigger('error', self, response, options);
    if (error) return error.apply(this, arguments);
  };

  options.complete = function( response, status, xhr ) {
    if (complete) return complete.apply(this, arguments);
  }

  Backbone.sync('create', this, options);
}
 0
Author: Throttlehead,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-06-17 17:14:15

Para cualquiera que todavía esté usando backbone.js en 2017, la respuesta aceptada no está funcionando.

Intenta eliminar la anulación toJSON() en el modelo wrapper y llama a toJSON en la colección cuando instancies el modelo wrapper.

new ModelWrapper(Collection.toJSON());
 0
Author: zeros-and-ones,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-01-13 01:25:13