Backbone: Agrega un método de "restablecimiento" a Backbone.Model

Creado en 31 jul. 2014  ·  22Comentarios  ·  Fuente: jashkenas/backbone

Necesitaba actualizar algunos de los datos de un modelo que venían del servidor. Actualmente, hay dos opciones: llamar Model.set , o establecer Model.attributes directamente. No quería que se registraran los cambios, pero tampoco podía usar silent porque necesitaba actualizar las vistas respectivas. Entonces, escribí un parche de mono:

Backbone.Model.prototype.reset = (attributes, options) ->
    attrs = attributes || {};
    if options.parse
      attrs = this.parse(attrs, options) || {}

    @set(attrs, options);
    <strong i="9">@changed</strong> = {};

¿Se preguntó por qué Backbone.Model no tiene un método de reinicio como Backbone.Collection ?

question

Comentario más útil

@thesmart , Model # set no desarma los atributos faltantes, por lo que creo que es necesario restablecer Model #.

Debería ser un requisito dar una razón al cerrar un problema. Me gustaría saber por qué @ akre54 cerró esto. Los modelos de backbone son deliberadamente primitivos y sin opiniones, sin embargo, la falta de restablecimiento de Model # expresa una opinión sobre cómo se utilizan los modelos. De http://backbonejs.org/#Getting -started

Filosóficamente, Backbone es un intento de descubrir el conjunto mínimo de primitivas de estructuración de datos (modelos y colecciones) e interfaz de usuario (vistas y URL) que son generalmente útiles al construir aplicaciones web con JavaScript.

Todos 22 comentarios

Reset es una trampilla de escape que le permite realizar fácilmente un renderizado eficiente a granel cuando sabe que lo necesita.

Para su caso, solo use set .

¿Se puede configurar sin ensuciar los cambios de atributos?

El 1 de agosto de 2014, a las 7:28 a.m., Jeremy Ashkenas [email protected] escribió:

Reset es una trampilla de escape que le permite realizar fácilmente un renderizado eficiente a granel cuando sabe que lo necesita.

Para su caso, solo use set.

-
Responda a este correo electrónico directamente o véalo en GitHub.

¿Llamar a Model.clear() antes de Model.set({}) funcionará en su caso? De esta manera, no extenderá los atributos actuales, sino que serán reemplazados. Model.clear() también admite la opción silenciosa si no desea activar dos eventos de "cambio" en el modelo.

Estoy de acuerdo en que falta este método. También pensé en usar model.clear() y model.set() en conjunto. Luego me encontré con el problema, que ahora activé el evento change dos veces.
Usar la opción silent al llamar a model.clear() no es una opción, porque también quiero que se active un evento change , cuando una propiedad se desarma.

Un método model.reset() tomaría un nuevo hash de atributos y llenaría este hash con valores undefined para las claves de atributos antiguos que no están presentes en el nuevo hash de atributo.

Model.prototype.reset = function(attrs, options) {
    for (var key in this.attributes) {
        if (key in attrs) continue;
        attrs[key] = void 0;
    }

    return this.set(attrs, options);
};

@lennerd

Qué pasa:

Model.prototype.reset = function(attrs, options) {
    for (var key in this.attributes) {
        this.unset(key, {silent:true});
    }
    return this.set(attrs, options);
};

No, esto no ayuda. Imagine que tiene una clave foo en el hash de atributos actuales del modelo, que no está presente en el nuevo hash attrs que pasa a model.reset() . Cuando escucho el evento change:foo , no se activará con el nuevo valor undefined , porque usamos model.unset() en modo silencioso.

Backbone.Model.prototype.reset = function(attrs, options) {
    for (var key in this.attributes) {
        this.unset(key, {silent:true});
    }
    return this.set(attrs, options);
};

var bar = new Backbone.Model();

bar.on('change', function(model) {
    console.log('The model bar has been changed.');
});

bar.on('change:foo', function(model, foo) {
    console.log('Foo has been changed to: ' + foo);
});

bar.set(foo, 'test');
// => The model bar has been changed.
// => Foo has been changed to: test

bar.reset({ foo2: 'test2' });
// => The model bar has been changed.
// Foo was resetted but no change event has been triggered.

http://jsfiddle.net/lennerd/3s1Ltwgu/

Genial, entiendo lo que quieres decir. Probablemente optaría por usar this.unset(key, options) anulando this.attributes explícitamente, pero eso es solo una cuestión de intercambiar attrs[key] = void 0; : panda_face:

Disculpe cualquier ignorancia que muestro, ya que todavía soy relativamente nuevo en backbone.js, pero el comportamiento que se está discutiendo suena como Model.fetch . La descripción dice:

Restablece el estado del modelo desde el servidor.

Parece que los eventos change todavía se activan pero no hacen que el modelo se "ensucie". ¿Hay alguna razón por la que no se pueda adoptar este enfoque cuando se busca restablecer los atributos en función de la respuesta del servidor? Me imagino que la única situación de este tipo que podría ocurrir es cuando un modelo cambia como efecto secundario de otra operación, pero en general tales efectos secundarios se consideran una mala programación y deben evitarse si es posible. Si no se puede evitar el efecto secundario, quizás tenga más sentido enviar un indicador de respuesta "actualizar modelo XYZ" en lugar de los atributos del nuevo modelo y activar un fetch cada vez que vea tal respuesta.

Nuevamente, perdonen cualquier ignorancia que esté exhibiendo en este comentario.

@kolorahl ,

Lo que el OP quiere lograr es borrar los atributos del modelo actual y pasar un nuevo JSON que se convierte en los nuevos atributos del modelo. De esta manera, realmente no queremos llegar al backend si ya tenemos el JSON.

De alguna manera estoy de acuerdo con @ lupugabriel1 con su método clear + set. Pero creo que esta es una funcionalidad que debe tenerse en cuenta. Algo como Backbone.Collection # reset

La razón por la que necesitaba esto es porque el mundo está cambiando. Backbone asume que Model # fetch () XHR es el método principal para cargar datos desde el servidor, pero estamos haciendo muchas más cosas usando websockets. Cuando los datos se envían al cliente, es redundante llamar a .fetch y necesitamos una forma decente de cargar los datos de forma lateral y aún así obtener un evento que se active.

¿Por qué no estás usando #set ?

@jridgewell porque #set ensuciará los atributos. Intentemos usar set y veamos qué sucede:

function callback(data_from_server) {
  console.info(data_from_server);
  m = new Backbone.Model(data_from_server);
  m.set('foo', 'what?', {silent: true});
  console.info(m.changedAttributes())
}

Resultado real:

{foo: 'bar'}
{foo: "what?"}

Resultado deseado:

{foo: 'bar'}
false

Establecer está bien para cuando el estado ha cambiado y no está sincronizado con el servidor, pero se necesita restablecer el modelo # porque no hay forma de marcar el estado como sincronizado con el servidor.

Terminé escribiendo un parche de mono diferente para esta función:

/**
 * Allow for side-loading data from the server, calling the sync event afterwards.
 * <strong i="6">@param</strong> attributes
 * <strong i="7">@param</strong> options
 */
Backbone.Model.prototype.sync_set = function(attributes, options) {
  var attrs = attributes || {};
  if (options.parse) {
    attrs = this.parse(attrs, options) || {}
  }

  this.set(attrs, options);
  this.changed = {};
  this.trigger('sync', this, attributes, options);
  return this;
}
function callback(data_from_server) {
  console.info(data_from_server);
  m = new Backbone.Model(data_from_server);
  m.set('foo', 'what?', {silent: true});
  console.info(m.changedAttributes())
}
{foo: 'bar'}
false

Esto probablemente también deba desarmar los elementos que faltan. No estoy seguro si Model # set (atributos) hace eso.

Como señaló @lennerd , llamar a clear() seguido de set() no es una buena opción, porque

1) Activa dos eventos change y
2) Si usa silent:true en la llamada clear , no obtendrá eventos de cambio en los atributos que no estaban configurados.

collection.reset() es muy intuitivo y creo que Model realmente podría beneficiarse de un método equivalente. Me encuentro tratando de usar model.reset(attrs) todo el tiempo, siempre decepcionado cuando no está allí. :(

Seguí adelante y creé una pequeña extensión para agregar un método de trabajo reset a Backbone.Modelo: Backbone-Model-Reset

De acuerdo: sería útil tenerlo de forma nativa. Necesitaba restablecer los atributos sin alterar el atributo 'id', como estaba haciendo clear (). Aquí está la esencia .

@thesmart , Model # set no desarma los atributos faltantes, por lo que creo que es necesario restablecer Model #.

Debería ser un requisito dar una razón al cerrar un problema. Me gustaría saber por qué @ akre54 cerró esto. Los modelos de backbone son deliberadamente primitivos y sin opiniones, sin embargo, la falta de restablecimiento de Model # expresa una opinión sobre cómo se utilizan los modelos. De http://backbonejs.org/#Getting -started

Filosóficamente, Backbone es un intento de descubrir el conjunto mínimo de primitivas de estructuración de datos (modelos y colecciones) e interfaz de usuario (vistas y URL) que son generalmente útiles al construir aplicaciones web con JavaScript.

Por lo que puedo decir, el modelo de datos de Backbone es incompatible con REST
porque no hay forma de modelar de forma segura el estado del servidor en el cliente después de una
Se ha construido el modelo. Construir un nuevo modelo es la única forma de obtener
un estado nuevo sin reinicio.

El martes 5 de julio de 2016, pgifford [email protected] escribió:

@thesmart https://github.com/thesmart , Model # set no se desarma falta
atributos, por lo que creo que es necesario restablecer el modelo #.

Debería ser un requisito dar una razón al cerrar un problema. Carné de identidad
me gustaría saber por qué @ akre54 https://github.com/akre54 cerró esto.
Los modelos troncales son deliberadamente primitivos y sin opiniones, sin embargo, el
La falta de reinicio de Model # expresa una opinión sobre cómo se utilizan los modelos. Desde
http://backbonejs.org/#Getting -started

Filosóficamente, Backbone es un intento de descubrir el conjunto mínimo de
estructuración de datos (modelos y colecciones) e interfaz de usuario (vistas y
URL) primitivas que generalmente son útiles al crear aplicaciones web
con JavaScript.

-
Estás recibiendo esto porque te mencionaron.
Responda a este correo electrónico directamente, véalo en GitHub
https://github.com/jashkenas/backbone/issues/3253#issuecomment -230586424,
o silenciar el hilo
https://github.com/notifications/unsubscribe/AARJLQ8-BGeV0X_owHVpyPQAdeiMweNMks5qSriDgaJpZM4CTBHH
.

Necesitaba un modelo reset y seguí adelante y lo hice en el _spirit_ de Backbone. Lo uso en mi extensión personal de Backbone.

Es mejor que un simple .clear seguido de un .set porque fusiona los valores predeterminados en el modelo, permitiendo que cualquier atributo pasado los anule como en la inicialización.

/**
 * Clears the model's attributes and sets the default attributes.
 * <strong i="10">@param</strong> {Object} attributes to overwrite defaults
 * <strong i="11">@param</strong> {Object} options  to pass with the "set" call.
 * <strong i="12">@return</strong> {Backbone.Model}  this object, to chain function calls.
 */
reset: function(attributes, options) {
    options = _.extend({ reset: true }, options);

    // ensure default params
    var defaults = _.result(this, 'defaults'),
        attrs = _.defaults(_.extend({}, defaults, attributes || {}), defaults);

    // apply
    this._reset(attrs, options);

    // triggers a custom event, namespaced to model in order
    // to avoid collision with collection's native reset event
    // when listening to a collection.
    if (!options.silent) this.trigger('model:reset', this, options);

    return this;
},

/**
 * Private method to help wrap reset with a custom behavior in child
 * classes.
 * <strong i="13">@param</strong>  {Object} attributes to overwrite defaults
 * <strong i="14">@param</strong>  {Object} options  to pass with the "set" call.
 */
_reset: function(attrs, options) {
    this.clear({ silent: true }).set(attrs, options);
},

Activa eventos de cambio ( change y change:attribute ) además del evento personalizado model:reset si no es silent: true . Se podría personalizar fácilmente para activar solo el evento model:reset , pero creo que los eventos de cambio siempre deberían activarse al restablecer un modelo.

He modificado un poco la solución de lennerd https://github.com/jashkenas/backbone/issues/3253#issuecomment -58789524.

Backbone.Model.prototype.reset = function(attrs, options) {
    var missing = {};
    for (var key in this.attributes) {
        if (key in attrs) continue;
        attrs[key] = undefined;
        missing[key] = true;
    }
    // trigger all change events at the same time
    this.set(attrs, options);
    // remove missing attributes completely
    for (var key in missing) {
        // no silent option here in case  attributes changed again meanwhile (edge case)
        this.unset(key)
    }
    return this;
};
¿Fue útil esta página
0 / 5 - 0 calificaciones