Создание вложенных моделей в Backbone с помощью Backbone-реляционного - PullRequest
12 голосов
/ 29 августа 2011

Я хотел бы использовать магистрально-реляционный , чтобы иметь вложенные модели в моем приложении backbone.js .

Мне удалось следовать примерам в документации для создания вложенных объектов (например, отношений «один ко многим»). Однако я не понимаю, как связать элементы нижнего уровня таким образом, чтобы обновлять объекты верхнего уровня. Я думаю, что рабочее приложение было бы очень полезным руководством.

Итак, мой вопрос: как мне расширить учебник по Todos , используя backbone-relational, чтобы:

  • можно добавлять / удалять подпункты для каждого элемента
  • двойной щелчок по любому подэлементу редактирует его (как и в оригинальном примере с Todo)
  • нажатие на элемент скрывает / раскрывает его подпункты
  • подэлементы не извлекаются отдельно, а являются просто атрибутом массива элементов Todo

Обновление : Я создал jsfiddle для этого вопроса . Пока что у меня есть:

  • Импортирован пример Todo, упомянутый выше
  • Создана модель TodoSubitem и коллекция TodoSubitemList
  • Изменена модель Todo для расширения RelationalModel вместо Model, с отношением HasMany к TodoSubitem
  • Добавлен subitem-template в HTML-код

Но я все еще не уверен, как:

  • добавить поле ввода для subitems, которое появляется только при нажатии Todo div
  • имеют данные подэлементов в качестве атрибута Todo объектов, но все еще имеют TodoSubitemView привязанные к ним элементы DOM (например, <li> теги).

Ответы [ 4 ]

11 голосов
/ 01 сентября 2011

Я не думаю, что я бы создал отдельный '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...
});
3 голосов
/ 19 июня 2014

После некоторой путаницы я нашел способ создать истинную вложенную модель:

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

В тот момент, когда модель используется (при переходе к отношениям на прототипе), она становится доступной, поэтому все работает.

3 голосов
/ 09 ноября 2012

Я не думаю, что вы можете создавать самосвязанные модели в Backbone-реляционных (как описано в другом ответе здесь).Когда я попробую это, я получаю сообщение об ошибке: для Backbone-реляционного необходимо определить relatedModel, прежде чем он сможет создать с ним отношения.

Итак, я изменил шаблон «многие ко многим», описанный вРеляционно-магистральная страница:

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

По сути, я создаю модель связывания, которая содержит ссылки на упоминаемую модель, чтобы эта модель связи была доступна для Backbone-реляционный, когда он определяет фактическую модель.

Я считаю удобным дать этой модели связи отдельную связь с обеими моделями данных в связи, чтобы любая из них могла выполнять реляционные поиски поиска.С другой стороны, вы можете просто вставить вторую модель в модель связи, но тогда связь будет однонаправленной, если вы явно не добавите свои собственные ссылки на модель связи в модель данных.

Давайте создадим модель «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 необходимо определить> до

// 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, и добавьте его к потомкам KingKong с помощью этой строки:

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

Затем вы можете добавить вспомогательные функции в модель Person, чтобы извлечь вложенные модели из модели FamilyRelationship, ибольше не нужно трогать FamilyRelation, кроме как для того, чтобы убедиться, что он сохраняется и извлекается соответствующим образом.

Для неиерархических отношений (скажем, «Друг», а не «Родитель / Ребенок», вам все еще нужны этидве связи с моделью связывания, чтобы иметь возможность извлекать одно из другого, что является чем-то вроде взлома, но это работает.

0 голосов
/ 17 июня 2016

этот пост уже довольно старый, но я искал то же самое и подумал, что поделюсь полученным решением.

Чтобы создать модель, ссылающуюся на себя, просто опустите relatedModel.Так что-то вроде этого:

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

Это объясняется в документах

...