underscore template backbonejs javascript json backbone.js backbone-collections

javascript - template - Asignación de colecciones JSON a backbone.js



backbonejs github (3)

De acuerdo, parece que necesito una pista para apuntarme en la dirección correcta. Esta pregunta tiene dos partes: trabajar con JSON multidimensional y Colecciones de colecciones de JSON.

Fondo

Tengo un JSON que se recuperará de un servidor y tengo control sobre cómo se puede formatear.

JSON multidimensional

Tengo problemas para conectar el modelo a las partes en el JSON. Digamos que quería representar solo cada uno de los posts nombre del autor , y el contenido del estado en la muestra JSON a continuación. No tengo problemas para obtener el estado en el modelo, pero el nombre del autor me da un poco de confusión sobre cómo llegar a él. Según tengo entendido, tengo que anular el análisis.

¿Son estos malos estándares / hay una mejor estructura JSON que debería usar? ¿Sería mejor mantenerlo lo más plano posible? ¿Eso es mover el nombre del autor y la foto a un nivel?

Estaba leyendo Cómo crear una Colección / Modelo desde JSON anidado con Backbone.js, pero aún no me queda claro.

Colección en Colecciones

¿Hay una buena manera de hacer una colección dentro de una colección para backbone.js? Tendré una colección de publicaciones y luego tendré una colección de comentarios sobre esa publicación. Como estoy desarrollando en la columna vertebral, ¿es eso posible?

Por lo que entiendo en Backbone.js Collection of Collections y Backbone.js Collection of Collections Issue , ¿se vería algo así?

var Comments = Backbone.Model.extend({ defaults : { _id : "", text : "", author : "" } }) var CommentsCollection = Backbone.Collection.extend({ model : Comments }) var Posts = Backbone.Model.extend({ defaults : { _id : "", author : "", status : "", comments : new CommentsCollection } }) var PostsCollection = Backbone.Collection.extend({ model : Posts })

Muestra JSON

{ "posts" : [ { "_id": "50f5f5d4014e045f000002", "author": { "name" : "Chris Crawford", "photo" : "http://example.com/photo.jpg" }, "status": "This is a sample message.", "comments": [ { "_id": "5160eacbe4b020ec56a46844", "text": "This is the content of the comment.", "author": "Bob Hope" }, { "_id": "5160eacbe4b020ec56a46845", "text": "This is the content of the comment.", "author": "Bob Hope" }, { ... } ] }, { "_id": "50f5f5d4014e045f000003", "author": { "name" : "Chris Crawford", "photo" : "http://example.com/photo.jpg" }, "status": "This is another sample message.", "comments": [ { "_id": "5160eacbe4b020ec56a46846", "text": "This is the content of the comment.", "author": "Bob Hope" }, { "_id": "5160eacbe4b020ec56a46847", "text": "This is the content of the comment.", "author": "Bob Hope" }, { ... } ] }, { ... } ]}

Agradezco incluso cualquier pista para guildme. ¡Gracias!


Puede ser abrumador cuando intenta escribir código para hacerlo funcionar para objetos anidados. Pero para hacerlo más simple, dividamos en partes manejables más pequeñas.

Yo pensaría en estas líneas.

Colecciones

Posts Comments

Modelos

Post Comment Author

Main collection -- Posts collection (Which contains list of Post Models)

Y each model in the Posts collection tendrá 3 conjuntos de atributos (puede que no sea el término correcto).

1º - nivel de atributos (estado, id).

2º - Atributo de autor que puede colocarse en un Modelo separado (Modelo de autorización).

3º - Colección de comentarios para cada modelo de publicación.

La colección en Colecciones sería un poco confusa aquí. Como tendrías Modelos en colección ( Post Model inside Posts Collection Colección de Post Model inside Posts Collection ) y cada Modelo anidará una colección nuevamente ( Comments collection inside Post Model ). Básicamente, estarías manejando una Collection inside a Model .

Según tengo entendido, tengo que anular el análisis.

¿Son estos malos estándares / hay una mejor estructura JSON que debería usar?

Es una solución perfectamente plausible para manejar el procesamiento esto en el método Parse. Cuando inicializa una Colección o un Modelo, primero se llama a los métodos Parse y luego se invoca. Por lo tanto, es perfectamente lógico manejar la lógica dentro del método Parse y no es en absoluto un mal estándar.

¿Sería mejor mantenerlo lo más plano posible?

No creo que sea una buena idea mantener este plano en un solo nivel, ya que los otros datos no son necesarios en el primer nivel en primer lugar.

Entonces, la forma en que abordaría este problema es escribir el método de parse en el Post Model que procesa la respuesta y adjuntar el modelo de autor y la colección de comentarios directamente en el modelo como un atributo en el modelo para mantener los atributos hash clean consistente en 1ra. nivel de datos de publicación. Esto creo que será más limpio y mucho más escalable a largo plazo.

var postsObject = [{ "_id": "50f5f5d4014e045f000002", "author": { "name": "Chris Crawford", "photo": "http://example.com/photo.jpg" }, "status": "This is a sample message.", "comments": [{ "_id": "5160eacbe4b020ec56a46844", "text": "This is the content of the comment.", "author": "Bob Hope" }, { "_id": "5160eacbe4b020ec56a46845", "text": "This is the content of the comment.", "author": "Bob Hope" }] }, { "_id": "50f5f5d4014e045f000003", "author": { "name": "Brown Robert", "photo": "http://example.com/photo.jpg" }, "status": "This is another sample message.", "comments": [{ "_id": "5160eacbe4b020ec56a46846", "text": "This is the content of the comment.", "author": "Bob Hope" }, { "_id": "5160eacbe4b020ec56a46847", "text": "This is the content of the comment.", "author": "Bob Hope" }] }]; // Comment Model var Comment = Backbone.Model.extend({ idAttribute: ''_id'', defaults: { text: "", author: "" } }); // Comments collection var Comments = Backbone.Collection.extend({ model: Comment }); // Author Model var Author = Backbone.Model.extend({ defaults: { text: "", author: "" } }); // Post Model var Post = Backbone.Model.extend({ idAttribute: ''_id'', defaults: { author: "", status: "" }, parse: function (resp) { // Create a Author model on the Post Model this.author = new Author(resp.author || null, { parse: true }); // Delete from the response object as the data is // alredy available on the model delete resp.author; // Create a comments objecton model // that will hold the comments collection this.comments = new Comments(resp.comments || null, { parse: true }); // Delete from the response object as the data is // alredy available on the model delete resp.comments; // return the response object return resp; } }) // Posts Collection var Posts = Backbone.Collection.extend({ model: Post }); var PostsListView = Backbone.View.extend({ el: "#container", renderPostView: function(post) { // Create a new postView var postView = new PostView({ model : post }); // Append it to the container this.$el.append(postView.el); postView.render(); }, render: function () { var thisView = this; // Iterate over each post Model _.each(this.collection.models, function (post) { // Call the renderPostView method thisView.renderPostView(post); }); } }); var PostView = Backbone.View.extend({ className: "post", template: _.template($("#post-template").html()), renderComments: function() { var commentsListView = new CommentsListView({ // Comments collection on the Post Model collection : this.model.comments, // Pass the container to which it is to be appended el : $(''.comments'', this.$el) }); commentsListView.render(); }, render: function () { this.$el.empty(); // Extend the object toi contain both Post attributes // and also the author attributes this.$el.append(this.template(_.extend(this.model.toJSON(), this.model.author.toJSON() ))); // Render the comments for each Post this.renderComments(); } }); var CommentsListView = Backbone.View.extend({ renderCommentView: function(comment) { // Create a new CommentView var commentView = new CommentView({ model : comment }); // Append it to the comments ul that is part // of the view this.$el.append(commentView.el); commentView.render(); }, render: function () { var thisView = this; // Iterate over each Comment Model _.each(this.collection.models, function (comment) { // Call the renderCommentView method thisView.renderCommentView(comment); }); } }); var CommentView = Backbone.View.extend({ tagName: "li", className: "comment", template: _.template($("#comment-template").html()), render: function () { this.$el.empty(); this.$el.append(this.template(this.model.toJSON())); } }); // Create a posts collection var posts = new Posts(postsObject, {parse: true}); // Pass it to the PostsListView var postsListView = new PostsListView({ collection: posts }); // Render the view postsListView.render();

Compruebe Fiddle


(Editado para corregir mi error de lectura inicial de la pregunta).

No es necesario anular el método de parse del modelo a menos que desee cambiar su estructura. Pero parece que no necesita hacerlo: para representar el nombre del autor, simplemente use author.name en la vista:

<%= author.name %>

En cuanto a la inicialización de la colección anidada, su enfoque es el correcto. Todo lo que tiene que hacer es convertir el objeto JSON en modelos Backbone y pasarlos a PostsCollection (el constructor Backbone.Collection acepta una matriz de modelos Backbone, no JSON sin formato). Una forma de hacerlo es usar el map :

var postModels = json.posts.map(function(post) { return new Posts(post); }); var posts = new PostsCollection(postModels);

Tenga en cuenta que deberá hacer algo similar en el método de initialize del modelo de Posts : recuperar la matriz JSON de comentarios y convertirla en una matriz de modelos de Comments :

initialize: function() { if (attributes.comments && attributes.comments.length > 0) { var commentModels = attributes.comments.map(function(comment) { return new Comments(comment); }); this.set("comments", new CommentsCollection(commentModels)); } }

Aquí está el ejemplo de trabajo.


Actualización, encontré un SuperModel para backbone que proporciona relaciones entre modelos y entre colecciones. Ha demostrado ser una gran solución para colecciones dentro de colecciones, así como datos de modelos anidados profundos.

Los modelos están predefinidos con sus relaciones con otros modelos a través de la clave. Durante la inicialización / análisis del modelo, cualquier valor en el JSON de esa clave pasa a un nuevo modelo o colección relacionado. Se crea una relación entre los dos modelos / colecciones.

Esto significa que con el ejemplo anterior podemos hacer algo como esto con nuestros modelos:

Preparar

var Author = Supermodel.Model.extend({}); var Post = Supermodel.Model.extend({}); var Comment = Supermodel.Model.extend({}); var Posts = Backbone.Collection.extend({ model: function(attrs, options) { return Post.create(attrs, options); } }); var Comments = Backbone.Collection.extend({ model: function(attrs, options) { return Comment.create(attrs, options); } }); Post.has().one(''author'', { model: Author, inverse: ''post'' }).many(''comments'', { collection: Comments, inverse: ''post'' }); //reverse relationships could also be setup

Uso

var posts = new Posts( postsObject ); //where postsObject is an array of posts //With SuperModel, we are able to navigate the related models posts.first().comments(); posts.first().comments().author(); posts.last().author();

Violín

Ejemplo de trabajo en JSFiddle