Подтвердить что ты не робот

Создание вложенных моделей в Backbone с Backbone-реляционными

Я хотел бы использовать backbone-relational, чтобы иметь вложенные модели в 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>).
4b9b3361

Ответ 1

Я не думаю, что в этом случае я бы создал отдельный "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...
});

Ответ 2

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

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

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 должно быть определено > до < Человек, поэтому Backbone-relational может создавать ссылки, поэтому это происходит до определения модели Person в вашем коде:

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

FamilyRelation = Backbone.RelationalModel.extend({
})

Если мы создадим два "Person" s:

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

Затем мы можем создать модель FamilyRelationship, которая является "parentof" SonOfKong, и добавить ее к детям KingKong с этой строкой:

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

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

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

Ответ 3

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

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

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

Ответ 4

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

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

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

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