12

我想使用主干关系在我的主干.js应用程序中嵌套模型。

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

所以我的问题是:如何扩展Todos 教程backbone-relational以便:

  • 可以为每个项目添加/删除子项目
  • 双击任何子项对其进行编辑(就像原始的 Todo 示例一样)
  • 点击一个项目隐藏/显示其子项目
  • 子项不单独获取,而只是 Todo 项的数组属性

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

  • 导入了上面提到的 Todo 例子
  • 创建TodoSubitem模型和TodoSubitemList集合
  • Todo模型更改为扩展RelationalModel而不是,ModelHasManyTodoSubitem
  • subitem-template在 html 代码中添加了一个

但我仍然不确定如何:

  • subitems添加仅在单击Tododiv时出现的输入字段
  • 将子项数据作为Todo对象的属性,但仍将TodoSubitemViewDOM 元素绑定到它们(例如<li>标签)。
4

4 回答 4

11

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

这样,您可以重新使用订单逻辑(如果您将其更改为按集合应用),可以根据需要创建更深的嵌套级别(或将其限制到一定深度,如果您也愿意)等等。不过,为了适应这一点,需要更新一些东西——例如,保留一个子视图列表,以便您可以遍历它们以将每个视图标记为已完成,并维护(和更新)每个TodoList.

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

//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...
});
于 2011-08-31T21:27:34.097 回答
3

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

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

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

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

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

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

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

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

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

FamilyRelation = Backbone.RelationalModel.extend({
})

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

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

然后我们可以创建一个 FamilyRelationship 模型,它是 SonOfKong 的 'parentof',并将其添加到 KingKong 的子代中:

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

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

对于非层次关系(比如“朋友”,而不是“父/子”,您仍然需要将这两个关系与链接模型联系起来,以便能够从另一个中检索一个,这有点小技巧,但是有用。

于 2012-11-09T17:31:10.430 回答
3

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

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

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

于 2014-06-19T14:55:53.713 回答
0

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

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

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

It is explained in the docs

于 2016-06-17T17:37:39.543 回答