javascript backbone.js backbone-relational

javascript - Creación de modelos anidados en Backbone con Backbone-relational



backbone.js (4)

No creo que crearía un ''TodoSubItem'' por separado en este caso, ¿por qué no crear una relación HasMany desde Todo-> Todo, para que Todo pueda tener 0 .. * children y 0..1 parent ?

De esta forma, puede reutilizar la lógica de orden (si la cambia para aplicar por colección), puede crear niveles de anidación más profundos como desee (o limitar eso a una cierta profundidad, si así lo desea), etc. Un número de sin embargo, habrá que actualizar las cosas para acomodar esto, por ejemplo, mantener una lista de vistas secundarias para que pueda recorrerlas para marcarlas como terminadas, y mantener (y actualizar) un pedido por TodoList .

De todos modos, un resumen de una posible solución para comenzar, como una especie de diferencia con su versión actual (lo siento, no está probado y podría contener errores horribles):

//Our basic **Todo** model has `text`, `order`, and `done` attributes. window.Todo = Backbone.RelationalModel.extend({ relations: [{ type: Backbone.HasMany, key: ''children'', relatedModel: ''Todo'', collectionType: ''TodoList'', reverseRelation: { key: ''parent'', includeInJSON: ''id'' } }], initialize: function() { if ( !this.get(''order'') && this.get( ''parent'' ) ) { this.set( { order: this.get( ''parent'' ).nextChildIndex() } ); } }, // Default attributes for a todo item. defaults: function() { return { done: false }; }, // Toggle the `done` state of this todo item. toggle: function() { this.save({done: !this.get("done")}); } nextChildIndex: function() { var children = this.get( ''children'' ); return children && children.length || 0; } }); // The DOM element for a todo item... window.TodoView = Backbone.View.extend({ //... is a list tag. tagName: "li", // Cache the template function for a single item. template: _.template($(''#item-template'').html()), // The DOM events specific to an item. events: { ''click'': ''toggleChildren'', ''keypress input.add-child'': ''addChild'', "click .check" : "toggleDone", "dblclick div.todo-text" : "edit", "click span.todo-destroy" : "clear", "keypress .todo-input" : "updateOnEnter" }, // The TodoView listens for changes to its model, re-rendering. initialize: function() { this.model.bind(''change'', this.render, this); this.model.bind(''destroy'', this.remove, this); this.model.bind( ''update:children'', this.renderChild ); this.model.bind( ''add:children'', this.renderChild ); this.el = $( this.el ); this.childViews = {}; }, // Re-render the contents of the todo item. render: function() { this.el.html(this.template(this.model.toJSON())); this.setText(); // Might want to add this to the template of course this.el.append( ''<ul>'', { ''class'': ''children'' } ).append( ''<input>'', { type: ''text'', ''class'': ''add-child'' } ); _.each( this.get( ''children'' ), function( child ) { this.renderChild( child ); }, this ); return this; }, addChild: function( text) { if ( e.keyCode == 13 ) { var text = this.el.find( ''input.add-child'' ).text(); var child = new Todo( { parent: this.model, text: text } ); } }, renderChild: function( model ) { var childView = new TodoView( { model: model } ); this.childViews[ model.cid ] = childView; this.el.find( ''ul.children'' ).append( childView.render() ); }, toggleChildren: function() { $(this.el).find( ''ul.children'' ).toggle(); }, // Toggle the `"done"` state of the model. toggleDone: function() { this.model.toggle(); _.each( this.childViews, function( child ) { child.model.toggle(); }); }, clear: function() { this.model.set( { parent: null } ); this.model.destroy(); } // And so on... });

Me gustaría usar backbone-relational para tener modelos anidados en mi aplicación backbone.js .

He podido seguir los ejemplos en la documentación para crear objetos anidados (por ejemplo, relaciones uno a muchos). Sin embargo, no entiendo cómo vincular los elementos de nivel inferior de una manera que actualice los objetos de nivel superior. Creo que una aplicación que funcione sería un tutorial muy útil.

Entonces mi pregunta es: ¿cómo extiendo el tutorial de Todos usando el backbone-relational para que:

  • uno puede agregar / eliminar subtemas para cada elemento
  • hacer doble clic en cualquier subelemento lo edita (al igual que el ejemplo original de Todo)
  • al hacer clic en un elemento se esconde / revela sus subelementos
  • los subelementos no se extraen por separado, sino que son simplemente un atributo de matriz de los elementos de Todo

Actualización : he creado un jsfiddle para esta pregunta . Hasta ahora tengo:

  • Importó el ejemplo de Todo mencionado anteriormente
  • Creó un modelo de TodoSubitem y una colección de TodoSubitemList
  • Alterado el modelo de Todo para extender RelationalModel lugar de Model , con una relación de TodoSubitem con TodoSubitem
  • Se agregó una subitem-template en el código html

Pero todavía no estoy seguro de cómo:

  • agregue un campo de entrada para los subitems que aparece solo cuando hace clic en un div Todo
  • tener datos de subtema como un atributo de los objetos de Todo , pero todavía tienen TodoSubitemView vinculando elementos DOM a ellos (por ejemplo, etiquetas <li> ).

No creo que puedas hacer modelos autorelacionados en Backbone-relational (como se describe aquí la otra respuesta). Cuando lo he intentado, aparece un error: Backbone-relational necesita que el RelatedModel se defina antes de que pueda crear relaciones con él.

Por lo tanto, modifiqué el patrón de muchos a muchos descrito en la página backbone-relational:

https://github.com/PaulUithol/Backbone-relational#many-to- many-relations

En esencia, estoy creando un modelo de vinculación para contener referencias al modelo al que se hace referencia, de modo que este modelo de enlace pueda estar disponible para Backbone-relational cuando está definiendo el modelo real.

Me parece conveniente dar a este modelo de enlace una relación separada con ambos modelos de datos en la relación, de modo que cualquiera de ellos pueda realizar búsquedas relacionadas con la apariencia. Alternativamente, podría rellenar el segundo modelo dentro del modelo de enlace, pero la relación sería unidireccional a menos que agregue explícitamente sus propias referencias al modelo de enlace en el modelo de datos.

Vamos a crear un modelo de "Persona" que tenga hijos que sean otros modelos de "Persona".

Person = Backbone.RelationalModel.extend({ relations: [ { type: ''HasMany'', key: ''Children'', relatedModel: ''FamilyRelation'', reverseRelation: { key: ''Childrenof'' } }, { type: ''HasMany'', key: ''Parent'', relatedModel: ''FamilyRelation'', reverseRelation: { key: ''Parentof'' } } ] });

FamilyRelation debe definirse> antes de <Persona, por lo que Backbone-relational puede crear los enlaces, por lo que esto va antes de la definición del modelo de persona en su código:

// FamilyRelation is link model between two "Person"s // to achieve the Fan/Admiree relation. FamilyRelation = Backbone.RelationalModel.extend({ })

Si creamos dos "Persona" s:

KingKong = new Person({name: ''KingKong''}); SonOfKong = new Person({name: ''SonOfKong''});

Entonces podemos crear un modelo FamilyRelationship que sea el "padre de" SonOfKong, y agregarlo a los niños de KingKong con esta línea:

KingKong.get("children").add({"parentof":SonOfKong});

A continuación, puede agregar funciones de conveniencia al modelo de persona, para recuperar los modelos anidados del modelo de relación familiar, y realmente no necesita tocar FamilyRelation, excepto para asegurarse de que se guarda y se recupera de manera apropiada.

Para las relaciones no jerárquicas (digamos ''Amigo'', en lugar de ''Padre / Hijo'', todavía necesita estas dos relaciones con el modelo de vinculación para poder recuperar una de la otra, lo que es un poco complicado, pero funciona.


Después de tocar el violín, he encontrado una manera de crear un verdadero modelo anidado:

var theModel = Backbone.RelationalModel.extend({ [...] }); theModel.prototype.relations.push({ type: Backbone.HasOne, key: ''key'', relatedModel: theModel });

En el punto donde se usa el modelo (al presionar a las relaciones en el prototipo) está disponible, lo que hace que todo funcione.


esta publicación ya es bastante antigua, pero estaba buscando lo mismo y pensé que compartiría la solución que obtuve.

Para crear un modelo de autorreferencia, simplemente omita relatedModel . Entonces algo como esto:

Person = Backbone.RelationalModel.extend({ relations: [{ type: ''HasMany'', key: ''Children'', }] })

Se explica en los documentos