javascript 将 JSON 映射到backbone.js 集合

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/17890439/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-27 10:00:12  来源:igfitidea点击:

Mapping JSON to backbone.js collections

javascriptjsonbackbone.jsbackbone.js-collections

提问by Sir.Nathan Stassen

Alright, it looks like I need a hint to point me in the right direction. This question is two part - working with mult-dimensional JSON and Collections of Collections from JSON.

好的,看来我需要一个提示来指明正确的方向。这个问题分为两部分 - 使用多维 JSON 和来自 JSON 的集合集合。

Background

背景

I have some JSON that is going to be retrieved from a server and have control over how it could be formatted.

我有一些将从服务器检索的 JSON,并且可以控制它的格式。

Multi-Dimentional JSON

多维JSON

I'm having some trouble being able connecting the model to the parts in the JSON. Say I wanted to render just each of the posts author name, and the content of statusin the sample JSON below. I'm having no problem getting the status into the model, but the author name I'm a bit confused how to get to it. From my understanding I have to override the parse.

我在将模型连接到 JSON 中的部分时遇到了一些麻烦。假设我只想在下面的示例 JSON 中呈现每个帖子author namestatus的内容。我将状态输入模型没有问题,但作者姓名我有点困惑如何获得它。根据我的理解,我必须覆盖解析。

Is this bad standards / is there a better JSON structure I should use? Would it be better to keep it as flat as possible? That is move the author name and photo up one level?

这是糟糕的标准/我应该使用更好的 JSON 结构吗?保持尽可能平坦会更好吗?那是将作者姓名和照片上移一级吗?

I was reading How to build a Collection/Model from nested JSON with Backbone.jsbut it is still a little unclear to me.

我正在阅读如何使用 Backbone.js 从嵌套的 JSON 构建集合/模型,但对我来说仍然有点不清楚。

Collection in Collections

收藏中的收藏

Is there a nice way to make a collection within a collection for backbone.js? I will have a collection of posts, and then would have a collection of comments on that post. As I'm developing in backbone is that even possible?

有没有一种很好的方法可以在backbone.js 的集合中创建一个集合?我将收集帖子,然后收集对该帖子的评论。当我在主干中开发时,这甚至可能吗?

From what I understand in Backbone.js Collection of Collectionsand Backbone.js Collection of Collections Issue, it would look something like this?

根据我在Backbone.js Collection of CollectionsBackbone.js Collection of Collections Issue 中的理解,它看起来像这样?

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

Sample JSON

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

I appreciate even any hints to guild me. Thanks!

我什至感谢任何提示来引导我。谢谢!

采纳答案by Sir.Nathan Stassen

Update, I found a SuperModelfor backbone which provides relationships between models and between collections. It has proved to be a great solution for Collections within Collections as well as Deep Nested Model data.

更新,我找到了一个用于主干的SuperModel,它提供了模型之间和集合之间的关系。事实证明,对于集合中的集合以及深度嵌套模型数据来说,它是一个很好的解决方案。

Models are pre-defined with their relationships to other models via key. During the initialize/parse of the model any values in the JSON at that key gets passed off to a new related model or collection. A relationship is created between the two models/collections.

模型通过键与其他模型的关系预先定义。在模型的初始化/解析过程中,该键的 JSON 中的任何值都会传递给新的相关模型或集合。在两个模型/集合之间创建了一种关系。

This means with the above example we can do something like this with our models:

这意味着在上面的例子中,我们可以用我们的模型做这样的事情:

Setup

设置

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

Usage

用法

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

JSFiddle 中的工作示例

回答by Sushanth --

It can be overwhelming when trying to write up code to make it work for nested objects. But to make it simpler lets break it up into smaller manageable pieces.

在尝试编写代码以使其适用于嵌套对象时,这可能会让人不知所措。但是为了让它更简单,让我们把它分解成更小的可管理的部分。

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 collectionwill have 3 sets of attributes(May not be the right term).

并且each model in the Posts collection将有 3 组属性(可能不是正确的术语)。

1st - level of attributes (status , id).

第一级 - 属性(状态,ID)。

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

第二个 - Author 属性,可以放置在单独的模型(Authod 模型)中。

3rd - Collection of comments for each Post Model.

3rd - 收集每个帖子模型的评论。

Collection in Collectionswould be a bit confusing here. As you would have Models in Collection(Post Model inside Posts Collection) and each Model will nest a collection again(Comments collection inside Post Model). Basically you would be Handling a Collection inside a Model.

Collections 中的 Collection在这里会有点混乱。就像您在 Collection( Post Model inside Posts Collection) 中拥有模型一样,每个模型将再次嵌套一个集合 ( Comments collection inside Post Model)。基本上你会处理一个Collection inside a Model.

From my understanding I have to override the parse.

Is this bad standards / is there a better JSON structure I should use?

根据我的理解,我必须覆盖解析。

这是糟糕的标准/我应该使用更好的 JSON 结构吗?

It is a perfectly plausible solution to handle the processing this in the Parse method. When you initialize a Collection or a Model , Parse methods is first called and then initialize is called. So it is perfectly logical to handle the logic inside the Parse method and it is not at all a bad standard.

在 Parse 方法中处理 this 是一个非常合理的解决方案。当您初始化 Collection 或 Model 时,首先调用 Parse 方法,然后调用 initialize 。因此,处理 Parse 方法内部的逻辑是完全合乎逻辑的,而且它根本不是一个糟糕的标准。

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

保持尽可能平坦会更好吗?

I don't think it is a good idea to keep this flat at a single level, as the other data is not required on the first level in the first place.

我认为将这个平面保持在单一级别并不是一个好主意,因为首先在第一级别不需要其他数据。

So the way I would approach this problem is write up the parsemethod in the Post Modelwhich processes the response and attach the Author model and Comments collection directly on the Model instead as an attribute on the Model to keep the attributes hash clean consisting of 1st level of Post data. This I feel will be cleaner and lot more scalable on the long run.

所以我解决这个问题的parse方法是写下Post Model处理响应的方法,并将作者模型和评论集合直接附加到模型上,而不是作为模型上的属性,以保持属性哈希干净,包括第一级 Post数据。从长远来看,我觉得这会更干净,更具可扩展性。

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 Fiddle

检查小提琴

回答by McGarnagle

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

(编辑以纠正我最初对问题的误读。)

There's no need to override parsemethod of the model unless you want to change its structure. But it sounds like you don't need to -- to render the author name, just use author.namein the view:

parse除非您想更改其结构,否则无需覆盖模型的方法。但听起来您不需要 - 呈现作者姓名,只需author.name在视图中使用:

<%= author.name %>

As far as initializing the nested collection, your approach is exactly right. All you have to do is convert the JSON object to Backbone models, and pass them to the PostsCollection(the Backbone.Collectionconstructor accepts an array of Backbone models, notraw JSON). One way of doing this is to use map:

至于初始化嵌套集合,你的方法是完全正确的。您所要做的就是将 JSON 对象转换为 Backbone 模型,并将它们传递给PostsCollectionBackbone.Collection构造函数接受一组 Backbone 模型,而不是原始 JSON)。这样做的一种方法是使用map

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

Note that you'll need to do something similar in the initializemethod of the Postsmodel -- retrieve the comments JSON array, and convert it to an array of Commentsmodels:

请注意,您需要initializePosts模型的方法中执行类似的操作——检索注释 JSON 数组,并将其转换为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));
    }
}

Here is working example.

这是工作示例。