javascript 使用 Backbone-relational 在 Backbone 中创建嵌套模型

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7227597/
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-25 23:22:56  来源:igfitidea点击:

Creating nested models in Backbone with Backbone-relational

javascriptbackbone.jsbackbone-relational

提问by Christopher DuBois

I would like to use backbone-relationalto have nested models in my backbone.jsapplication.

我想使用backbone-relational在我的backbone.js应用程序中嵌套模型。

I have been able to follow the examples in the documentation to create nested objects (e.g. one-to-many relations). However I don't understand how to bind the lower level elements in a way that will update the upper level objects. I think a working application would be a very helpful tutorial.

我已经能够按照文档中的示例创建嵌套对象(例如一对多关系)。但是我不明白如何以更新上层对象的方式绑定下层元素。我认为一个有效的应用程序将是一个非常有用的教程。

So my question is: How do I extend the Todos tutorialusing backbone-relationalso that:

所以我的问题是:如何使用以下方式扩展Todos 教程backbone-relational

  • one can add/remove subitems for each item
  • double clicking on any subitem edits it (just like the original Todo example)
  • clicking on an item hides/reveals its subitems
  • subitems are not fetched separately but are simply an array attribute of Todo items
  • 可以为每个项目添加/删除子项目
  • 双击任何子项对其进行编辑(就像原始 Todo 示例一样)
  • 点击一个项目隐藏/显示其子项目
  • 子项不会单独获取,而只是 Todo 项的数组属性

Update: I have created a jsfiddle for this question. So far I have:

更新:我为这个问题创建了一个 jsfiddle。到目前为止,我有:

  • Imported the Todo example mentioned above
  • Created a TodoSubitemmodel and a TodoSubitemListcollection
  • Altered the Todomodel to extend RelationalModelinstead of Model, with a HasManyrelation to TodoSubitem
  • Added a subitem-templatein the html code
  • 导入上面提到的Todo例子
  • 创建了一个TodoSubitem模型和一个TodoSubitemList集合
  • 改变了Todo模型扩展RelationalModel,而不是Model,有HasMany关系TodoSubitem
  • subitem-template在html代码中添加了一个

But I'm still not sure how to:

但我仍然不确定如何:

  • add an input field for subitemsthat appears only when you click a Tododiv
  • have subitem data as an attribute of Todoobjects, but still have TodoSubitemViewbind DOM elements to them (e.g. <li>tags).
  • 添加一个subitems仅在您单击Tododiv时出现的输入字段
  • 将子项目数据作为Todo对象的属性,但仍将TodoSubitemViewDOM 元素绑定到它们(例如<li>标签)。

采纳答案by Paul

I don't think I'd create a separate 'TodoSubItem' in this case - why not create a HasManyrelation from Todo->Todo, so a Todo can have 0..* children, and 0..1 parent?

我不认为在这种情况下我会创建一个单独的“TodoSubItem”——为什么不HasMany从 Todo->Todo创建一个关系,这样一个 Todo 可以有 0..*children和 0..1 parent

This way, you can re-use the order logic (if you change it to apply per collection), can create deeper nesting levels as desired (or limit that to a certain depth, if you want as well), etc. A number of things will need to be updated though, to accomodate this - for example, keep a list of child views so you can loop over them to mark each as done, and maintaining (and updating from) an ordering per TodoList.

这样,您可以重新使用顺序逻辑(如果您将其更改为应用到每个集合),可以根据需要创建更深的嵌套级别(或将其限制为某个深度,如果您愿意的话)等。事情需要更新,以适应这一点 - 例如,保留一个子视图列表,以便您可以遍历它们以将每个视图标记为已完成,并维护(和更新)每个TodoList.

Anyway, a rough outline of a possible solution to get you started, as a sort of diff with your current version (sorry, it's completely untested and could thus contain horrible mistakes):

无论如何,粗略概述一个可能的解决方案来帮助您入门,作为与您当前版本的一种差异(抱歉,它完全未经测试,因此可能包含可怕的错误):

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

回答by Jon Biz

I don't think you can make self-relating models in Backbone-relational (as described an the other answer here). When I have tried this, I get an error: Backbone-relational needs the relatedModel to be defined before it can create relationships with it.

我认为您不能在 Backbone-relational 中创建自相关模型(如此处的另一个答案所述)。当我尝试此操作时,出现错误:Backbone-relational 需要先定义相关模型,然后才能与其建立关系。

So, I've modified the many-to-many pattern described on the backbone-relational page:

所以,我修改了主干关系页面上描述的多对多模式:

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

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

In essence, I am creating a linking model to contain references to the model being referred to, so that this link model can be available to Backbone-relational when it is defining the actual model.

本质上,我正在创建一个链接模型来包含对所引用模型的引用,以便在定义实际模型时,此链接模型可用于 Backbone-relational。

I find it convenient to give this link model a separate relationship with both data models in the relationship, so that either can perform look relational look ups. Alternately, you could simply stuff the second model inside the link model, but then the relationship would be one directional unless you explicitly add your own references to the link model in the data model.

我发现给这个链接模型一个单独的关系与关系中的两个数据模型很方便,这样任何一个都可以执行查找关系查找。或者,您可以简单地将第二个模型填充到链接模型中,但除非您在数据模型中明确添加自己对链接模型的引用,否则关系将是单向的。

Let us create a 'Person' model that has children who are other 'Person' models.

让我们创建一个“人”模型,其中包含其他“人”模型的子代。

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

FamilyRelation needs to be defined >before< Person is, so Backbone-relational can create the links, so this goes before the Person model definition in your code:

FamilyRelation 需要在 >before< Person 之前定义,所以 Backbone-relational 可以创建链接,所以这在代码中的 Person 模型定义之前:

// FamilyRelation is link model between two "Person"s 
// to achieve the Fan/Admiree relation.

FamilyRelation = Backbone.RelationalModel.extend({
})

If we create two "Person"s:

如果我们创建两个“人”:

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

Then we can create a FamilyRelationship model that is the 'parentof' SonOfKong, and add it to KingKong's children with this line:

然后我们可以创建一个 FamilyRelationship 模型,它是 SonOfKong 的“父母”,并使用以下行将其添加到 KingKong 的孩子:

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

You can then add convenience functions to the Person model, to retrieve the nested models from the FamilyRelationship model, and don't really need to touch FamilyRelation any more, except to make sure it's being saved and retrieved appropriately.

然后,您可以向 Person 模型添加便利函数,以从 FamilyRelationship 模型中检索嵌套模型,并且实际上不再需要接触 FamilyRelation,除非确保它被正确地保存和检索。

For non-hierarchical relationships (say 'Friend', rather than 'Parent/Child', you still need these two relationships with the linking model in order to be able to retrieve one from the other, which is a bit of a hack, but it works.

对于非层次关系(比如“朋友”,而不是“父/子”,您仍然需要使用链接模型的这两个关系才能从另一个关系中检索一个,这有点麻烦,但是有用。

回答by Ronald Mansveld

After some fiddling I have found a way to create a true nested model:

经过一番折腾,我找到了一种创建真正嵌套模型的方法:

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

At the point where the model is used (when pushing to the relations on the prototype) it is available, thus making everything work.

在使用模型时(当推送到原型上的关系时)它可用,从而使一切正常。

回答by tvdw

this post is pretty old by now, but I was searching for the same thing and thought I would share the solution I got.

这篇文章现在已经很老了,但我正在寻找同样的东西,并认为我会分享我得到的解决方案。

To create a self-referencing model you simply omit relatedModel. So something like this:

要创建自引用模型,您只需省略relatedModel. 所以像这样:

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

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

It is explained in the docs

在文档中解释