12

backbone.jsアプリケーションでモデルをネストするためにbackbone-relationalを使用したいと考えています。

ドキュメントの例に従って、ネストされたオブジェクト (1 対多の関係など) を作成することができました。ただし、上位レベルのオブジェクトを更新する方法で下位レベルの要素をバインドする方法がわかりません。実用的なアプリケーションは非常に役立つチュートリアルになると思います。

だから私の質問は次のとおりです。次のように使用してTodos チュートリアルを拡張するにはどうすればよいですかbackbone-relational

  • 各アイテムのサブアイテムを追加/削除できます
  • サブアイテムをダブルクリックすると、それが編集されます (元の Todo の例と同様)
  • 項目をクリックすると、そのサブ項目が非表示/表示されます
  • サブアイテムは個別に取得されるのではなく、単純に Todo アイテムの配列属性です

更新:この質問のために jsfiddle を作成しました。これまでのところ、私は持っています:

  • 上記の Todo の例をインポートしました
  • TodoSubitemモデルとTodoSubitemListコレクションを作成しました
  • の代わりにTodo拡張するようにモデルを変更しました。RelationalModelModelHasManyTodoSubitem
  • subitem-templatehtml コードにa を追加しました

しかし、私はまだ方法がわかりません:

  • divsubitemsをクリックしたときにのみ表示される入力フィールドを追加しますTodo
  • Todoオブジェクトの属性としてサブアイテム データを持ちますがTodoSubitemView、それらに DOM 要素をバインドします (<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

バックボーンリレーショナルで自己関連モデルを作成できるとは思いません(ここで他の回答で説明されているように)。これを試してみると、エラーが発生します。バックボーンリレーショナルは、関係を作成する前に、関連モデルを定義する必要があります。

そのため、バックボーン リレーショナル ページで説明されている多対多のパターンを変更しました。

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

本質的には、参照されているモデルへの参照を含むリンク モデルを作成しているため、実際のモデルを定義するときに、このリンク モデルをバックボーン リレーショナルで使用できます。

このリンク モデルに、リレーションシップ内の両方のデータ モデルとの別のリレーションシップを与えると、どちらもルック リレーショナル ルックアップを実行できるので便利です。別の方法として、単純に 2 番目のモデルをリンク モデル内に詰め込むこともできますが、データ モデル内のリンク モデルへの独自の参照を明示的に追加しない限り、関係は一方向になります。

他の「人」モデルである子を持つ「人」モデルを作成しましょう。

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

2 つの "Person" を作成する場合:

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

次に、SonOfKong の「親」である FamilyRelationship モデルを作成し、次の行で KingKong の子に追加します。

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

次に、Person モデルに便利な関数を追加して、FamilyRelationship モデルからネストされたモデルを取得できます。FamilyRelation を適切に保存および取得することを確認する以外は、FamilyRelation に実際に触れる必要はありません。

非階層関係 (「親/子」ではなく「友人」など) の場合、一方を他方から取得できるようにするために、リンク モデルとのこれら 2 つの関係が必要ですが、これはちょっとしたハックですが、できます。

于 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 に答える