2011-06-15 14 views
7

Usando backbone.js, aquí hay una prueba rápida para demostrar el problema que estoy enfrentando con modelos anidados.backbone.js modelos que apuntan a la misma instancia de modelo anidado

Prefacio que tienen un modelo Obj que contiene 2 modelos anidados, Obj1 y Obj2. El modelo Obj en sí tiene una Vista (ObjView), y hay una Vista para la página principal en sí (BodyView).

La página principal tiene un solo botón, id = add. Cada vez que se hace clic en el botón, se agrega un nuevo Obj a ObjCollection, y ObjView agrega un botón (id = clickMe) a la página. El botón clickMe está vinculado a un testFunc que console.logs this.model y this.model.get ("obj1").

Problema De la inspección de los console.logs, veo que mientras cada obj es una nueva instancia, su punto de anidado Obj1 a la misma instancia de un obj1! Pero se supone que cada instancia de Obj tiene sus propias instancias de los modelos anidados obj1 y obj2.

Cualquier ayuda apreciada.

$(document).ready(function(){ 

    var Obj1 = Backbone.Model.extend({ 
     defaults:{ 
      Attr1A : false, 
      Attr1B : false 
     } 
    }) 

    var Obj2 = Backbone.Model.extend({ 
     defaults:{ 
      Attr2A : false, 
      Attr2B : false 
     } 
    }) 

    var Obj = Backbone.Model.extend({ 
     defaults: { 
      obj1 : new Obj1(), 
      obj2 : new Obj2() 
     } 
    }) 

    var ObjCollection = Backbone.Collection.extend({ 
     model: Obj 
    }); 


    var ObjView = Backbone.View.extend({ 

     initialize: function(){ 
      _.bindAll(this, 'render', 'testFunc'); 
      this.model.bind('change', this.render); 
      this.model.view = this; 

      $("body").append(this.render().el); 
     }, 

     events: { 
      "click #clickMe" : "testFunc" 
     }, 

     render: function(){ 
      $(this.el).html('<input type ="button" id="clickMe" value="Click">') 
      return this; 
     }, 

     testFunc: function(){ 
      console.log(this.model); //returns Obj models with unique cids 
      console.log(this.model.get("obj1")); //returns Obj1 models with the SAME cid! 
     } 
    }); 


    var BodyView = Backbone.View.extend({ 
     el: $('body'), 

     events:{ 
      "click #add" : "addObj" 
     }, 

     initialize: function(){ 
      _.bindAll(this, 'render', 'addObj') 
      this.collection = new ObjCollection(); 
      this.collection.bind('add', this.appendObj); 
     }, 

     addObj: function(){ 
      var myObj = new Obj(); 
      this.collection.add(myObj); 
     }, 

     appendObj: function(myObj){ 
      var objView = new ObjView({ 
       model: myObj 
      }); 
     } 
    }); 
    var bodyView = new BodyView; 

}); 

página El html es sólo el sigue con jQuery y la columna vertebral cargado.

<body> 
    <input type ="button" id="add" value="Add"> 
</body> 

Respuesta

5

fortuneRice, cuando se inicializa un modelo Backbone, el super.constructor mueve los valores predeterminados a la matriz de atributos internos, donde model.get busca "obj1". El ejemplo de Prusse inicializa los valores obj1 y obj2 con nuevos objetos para cada instancia, pero no mueve los valores a la matriz de atributos internos. Aquí está mi modificación de la solución de Prusse.

var Obj = Backbone.Model.extend({ 
    initialize: function() { 
     myDefaults = { 
      obj1: new Obj1(); 
      obj2: new Obj2(); 
     } 
     this.set(myDefaults); 
}); 

jQuery's extend método combinaría los dos objetos. Puede declarar las referencias no objetivas con los valores predeterminados y el objeto hace referencia con myDefaults en el método de inicialización.

+0

gracias por la clara explicación. – fortuneRice

+0

¿por qué no utilizar 'this.set (myDefaults)' en lugar de '$(). Extender (...)'? Internamente, hace lo mismo y tendrá el mismo efecto, pero creo que usar el set es más limpio. – idbentley

+0

@idbentley ¡oh, supongo que podrías hacer eso! Ni siquiera pensé en eso, pero sí, sería más limpio. Dispara el evento de cambio usando set, pero puede usar la opción de silencio así que supongo que eso realmente no importa. – c3rin

3

Con:

var Obj = Backbone.Model.extend({ 
    defaults: { 
     obj1 : new Obj1(), 
     obj2 : new Obj2() 
    } 
}) 

Usted está diciendo que desea que todos los objetos creados con "obj" tengan la misma "obj1" y los valores "obj2", utilice:

var Obj = Backbone.Model.extend({ 
    initialize: function() { 
     this.obj1 = new Obj1(); 
     this.obj2 = new Obj2(); 
    } 
}); 

Para lograr lo que has visto que quieres. http://documentcloud.github.com/backbone/#Model-constructor

+0

gracias por la ayuda, pero no estoy seguro de por qué 'this.model.get (" obj1 ")' ahora me da 'undefined'? Pensé que sería un error devolver una instancia de Obj1. ¿Algunas ideas? – fortuneRice

+0

@fortuneRice Pruebe 'this.get (" obj1 ")', obj1 no es un atributo del Obj de "clase" sino de las instancias de Obj. – Prusse

+0

gracias por el seguimiento; Acepté la solución de c3rin en base a la explicación sobre la matriz de atributos internos. – fortuneRice

Cuestiones relacionadas