2012-03-09 17 views
17

Tengo un escenario en el que los datos que se manipulan en el cliente se presentan y se interactúan de una manera diferente a como se representa en el servidor.Propiedades calculadas en backbone

Tenga en cuenta el siguiente recurso event devuelto por el servidor.

{ 
    "id": 123, 
    "start_at": 1331336004906, 
    "end_at": 1331337704906 
} 

Y la siguiente plantilla para la edición:

<form> 
    <!-- Notice how date and time are separated in the interface --> 
    <input type="text" name="start_date" value="{{start_date}}" /> 
    <input type="text" name="start_time" value="{{start_time}}" /> 

    <!-- Instead of asking for an end date/time, we ask for the duration --> 
    <input type="text" name="duration" value="{{duration}}" /> 

    <input type="submit" /> 
</form> 

¿Cómo hago para tratar start_date, start_time y duration como atributos en mi modelo Backbone sin enviarlos al servidor? ¿Se supone que debo modificar .toJSON()?

+0

¿cuál es el problema con el formato ressource evento, que enviaban las marcas de tiempo? – mpm

+0

Vea también: http://stackoverflow.com/questions/10648990/how-to-access-a-calculated-field-of-a-backbone-model-from-handlebars-template –

Respuesta

4

Su modelo debe corresponderse lo más posible con el lado del servidor. Así que quédese con start_at y end_at. Eso simplificará en gran medida sus operaciones sync().

En su formulario de edición Ver, puede:

  1. Calcular start_date, start_time, duration a través de funciones simples y los llaman en la plantilla.
  2. Convierte a start_at y end_at al enviar.
+1

No está poniendo esto en la vista va a conducir a una gran cantidad de código redundante? Utilizaré los mismos atributos virtuales en todo el sitio, donde un único evento tiene múltiples vistas que lo muestran. – bloudermilk

+0

Sin redundancia necesaria. Haga una vista base y extiéndala. – ggozad

+1

¡Buena llamada! También creo que el patrón decorador podría adaptarse a este problema. – bloudermilk

6

Estamos muy acostumbrados a enviar a model.toJSON()alimentar la plantilla. Y este método es muy difícil de sobreescribir porque lo utilizan otros componentes.

Pero podemos alimentar a la plantilla con un método personalizado model.toJSONDecorated() que puede tener este aspecto:

# in your Backbone.Model 
toJSONDecorated: function(){ 
    return 
    _.extend( 
     this.toJSON(), 
     { 
     start_date : Utils.dateFromDate(this.get("start_at")), 
     start_time : Utils.timeFromDate(this.get("start_at")), 
     duration : Utils.youGetTheIdea(:)) 
     } 
    ); 
} 

Por supuesto, esto es romper algunos patrones, puedo vivir con ella, si no lo hace se puede mueva esta lógica a una clase Decorator como las personas han sugerido en otras respuestas.

5

usted tiene algunas opciones:

  • Anulación toJSON para devolver el computada duration

  • crear un método duration() en el Backbone Model. El único inconveniente es que debe llamarlo de manera diferente (obj.duration() en lugar de obj.get('duration')). En su opinión de que las manos obj.toJSON() a la plantilla, se mezcla en el atributo duration

  • Uso https://github.com/asciidisco/Backbone.Mutators (o similar) para crear un captador derivada de duración

+0

Gracias. Generalmente adopto el enfoque descrito, pero no conozco Mutators: parece muy útil y bien hecho. –

22

estoy usando una combinación de la initialize() funcionan junto con los detectores de eventos de cambio para actualizar los atributos derivados. La idea es primero calcular los atributos en la inicialización del modelo, y segundo para permitir que el modelo escuche sus propios cambios y actualice los atributos en consecuencia.

Mi solución se ve más o menos así:

MyModel: Backbone.Model.extend({ 
    initialize: function() { 
     this.updateDerivedAttributes(); 
     this.on('change:start_at', this.updateDerivedAttributes, this); 
    }, 
    updateDerivedAttributes: function() { 
     this.set({ 
      start_date: Utils.dateFromDate(this.get("start_at")), 
      start_time: Utils.timeFromDate(this.get("start_at")), 
      duration: Utils.youGetTheIdea() 
     }, {silent:true}); 
    } 
});