7

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

背景

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

多维 JSON

我无法将模型连接到 JSON 中的部分。假设我只想渲染每个帖子author name以及下面示例 JSON 中的status内容。我将状态输入模型没有问题,但作者姓名我有点困惑如何获得它。据我了解,我必须覆盖解析。

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

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

收藏中的收藏

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

根据我在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 })

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

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

4

3 回答 3

13

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

我会在这些方面思考。

收藏品

 Posts
 Comments

楷模

 Post
 Comment
 Author

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

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

第一级属性(状态,id)。

2nd - 可以放置在单独模型(Authod 模型)中的作者属性。

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

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

据我了解,我必须覆盖解析。

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

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

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

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

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

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

检查小提琴

于 2013-07-26T21:30:39.797 回答
3

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

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

<%= author.name %>

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

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

请注意,您需要在模型的initialize方法中执行类似的操作Posts——检索评论 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));
    }
}

这是工作示例。

于 2013-07-26T21:15:08.220 回答
0

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

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

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

设置

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

用法

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

小提琴

JSFiddle 中的工作示例

于 2014-12-11T00:16:06.933 回答