JSON mapping to backbone.js collections

Well, it looks like I need a hint to point me in the right direction. This question has two parts - working with multidimensional JSON and collection collections from JSON.

Background

I have JSON that will be received from the server and will control how it can be formatted.

Multidimensional JSON

I am having trouble connecting the model to parts of JSON. Let's say I wanted to display only each post author name and status content in the JSON sample below. I have no problem getting status in the model, but the name of the author I'm a little confused about how to get to it. In my opinion, I should redefine the parsing.

Are these bad standards / is there a better JSON framework I should use? Would it be better to keep it as flat as possible? Does it move the author’s name and photo one level?

I read How to assemble a collection / model from nested JSON using Backbone.js , but I'm still a bit unclear.

Collection in collections

Is there a good way to make a collection in a collection for backbone.js? I will have a summary of posts, and then a summary of comments for this post will be compiled. How do I develop in the spine, is this possible?

From what I understand in Backbone.js Collection Collections and Backbone.js Collection Collections Issue , will it look something like this?

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 }) 

JSON example

 { "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" }, { ... } ] }, { ... } ]} 

I appreciate even any hints of a guild. Thanks!

+7
json javascript backbone-collections
source share
3 answers

Update, I found SuperModel for the backbone that provides relationships between models and between collections. This turned out to be a great solution for collections in collections, as well as for data from the Deep Nested Model.

Models are predefined with their relationship to other models using a key. During initialization / parsing of the model, any values ​​in JSON on this key are transferred to the new associated model or collection. A relationship is created between the two models / collections.

This means that in the above example, we can do something similar with our models:

Customization

 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 

Using

 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(); 

Fiddle

Working example in JSFiddle

0
source share

This can be overwhelming when trying to write code to make it work for nested objects. But to make it easier, you can break it down into smaller manageable parts.

I would think in these lines.

Collections

  Posts Comments 

Models

  Post Comment Author 

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

And each model in the Posts collection will have 3 sets of attributes (may not be the right term).

1st level of attributes (status, identifier).

2nd - Author attribute, which can be placed in a separate model (Authod model).

3rd - Collect comments for each publication model.

Collection in collections will be a little confusing here. Since you have models in the collection ( Post Model inside Posts Collection ), and each model will again embed the collection ( Comments collection inside Post Model ). You will mainly handle Collection inside a Model .

In my opinion, I should redefine the parsing.

Are these bad standards / is there a better JSON framework I should use?

This is a completely plausible solution to handle the processing of this Parse method. When you initialize a collection or model, analysis methods are called first, and then initialization is called. Therefore, it is logical to process the logic inside the Parse method, and this is not a bad standard at all.

Would it be better to keep it as flat as possible?

I do not think that it is a good idea to keep this apartment on the same level, since other data is not required on the first level in the first place.

So, I would approach this problem: write a parse method in the Post Model , which processes the response and attaches the author’s model and a collection of comments directly to the model instead as a Model attribute to store the hash clean attribute, which consists of the 1st level of Post data. I find this cleaner and more scalable in the long run.

 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(); 

Check script

+13
source share

(Edited to correct my initial misunderstanding of the question.)

There is no need to override the parse method of the model if you do not want to change its structure. But it doesn't seem like you need to - to make the author name, just use author.name in the view:

 <%= author.name %> 

Regarding initializing a nested collection, your approach is exactly the right one. All you have to do is convert the JSON object to Backbone models and pass them to PostsCollection (the Backbone.Collection constructor accepts an array of Backbone models, not raw JSON). One way to do this is to use map :

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

Note that you need to do something similar in the initialize method of the Posts model - get an array of JSON comments and convert it to an array of Comments models:

 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)); } } 

Here is a working example.

+3
source share

All Articles