Backbone.js структурирование вложенных представлений и моделей

Использование backbone.js:

У меня есть модель верхнего уровня ModelA, которая содержит 2 атрибута и 2 вложенные модели ModelB и ModelC. ModelB и ModelC имеют 2 атрибута следующим образом:

ModelA
    attributeA1
    attributeA2
    ModelB
        attributeB1
        attributeB2
    ModelC
        attributeC1
        attributeC2

Существует ViewA для ModelA и ViewB для ModelB. Функция рендеринга ViewA помещает новый div в тело, тогда как ViewB render создает h1. ViewA инициализирует вызовы ViewB, чтобы вставить этот h1 в новый div. Обоснованием этого разделения является то, что h1 может измениться и потребовать повторного рендеринга независимо от ViewA.

ViewA
    initialise: 
        //call ViewA own render function
        this.render() 

        //call ViewB render function that further modifies the $("#new") div created earlier.
        $("#new").append(ViewB.render().el)

    //ViewA own render function
    render: //place <div id="new"></div> onto 'body'

ViewB
    render: //create a <h1></h1>
    funcB1: //can this access it parent ModelA attributes and other objects?

Q1: ViewB имеет функцию funcB1. Может ли эта функция получить доступ к родительским атрибутам модели? Атрибуты, такие как атрибутA1 или даже атрибут C1 (который будет братом/кузеном)?

Q2: Как дальнейшее расширение до Q1, может ли funcB1 получить доступ к элементам DOM, связанным с ViewA? (в этом примере #new div?)

Q3: В общем, как я могу определить ассоциации между представлениями и моделями, как описано выше, чтобы все правильно соединилось?

Я понимаю, что этот вопрос несколько абстрактен, но любой ценит любую помощь или рекомендации, оцененные.

Ответ 1

Чтобы иметь возможность получать атрибуты на связанных моделях, модель должна иметь какие-то знания о том, к каким моделям она относится. Backbone.js не подразумевает отношения с отношениями или вложенности, что означает, что вы должны сами убедиться, что модели знают друг друга. Чтобы ответить на ваши вопросы, один из способов сделать это - убедиться, что каждая дочерняя модель имеет атрибут "parent". Таким образом, вы можете перенести вложенность сначала до родителя, а затем вниз к любому родному брату, о котором вы знаете.

Чтобы быть более конкретным с вашими вопросами. При инициализации modelA вы, вероятно, создаете modelB и modelC, я бы предложил установить ссылку на родительскую модель при этом, например:

ModelA = Backbone.Model.extend({

    initialize: function(){
        this.modelB = new modelB();
        this.modelB.parent = this;
        this.modelC = new modelC();
        this.modelC.parent = this;
    }
}

Таким образом, вы можете достичь родительской модели в любой дочерней модели, вызвав this.parent.

Что касается ваших взглядов, то при создании вложенных представлений с базой данных я считаю, что каждый вид представляет собой один тег HTML с помощью параметра tagName представления. Я бы написал ваши мнения как это:

ViewA = Backbone.View.extend({

    tagName: "div",
    id: "new",

    initialize: function(){
       this.viewB = new ViewB();
       this.viewB.parentView = this;
       $(this.el).append(this.viewB.el);
    }
});

ViewB = Backbone.View.extend({

    tagName: "h1",

    render: function(){
        $(this.el).html("Header text"); // or use this.options.headerText or equivalent
    },

    funcB1: function(){
        this.model.parent.doSomethingOnParent();
        this.model.parent.modelC.doSomethingOnSibling();
        $(this.parentView.el).shakeViolently();
    }

});

Затем в коде инициализации вашего приложения (например, в вашем контроллере) я бы инициировал ViewA и поместил его элемент внутри элемента body.

Ответ 2

Общий ответ на вопрос "Могу ли я" всегда "да, если вы готовы написать код". Точка за Backbone - обеспечить сильное разделение модели и представления. Если B1 имеет ссылку на A1, а A1 имеет ссылку на C1, то вы полностью можете создавать методы и устанавливать правила, с помощью которых B1 может изменять A1 и C1 и т.д.

Представления должны быть настроены для приема событий CRUD из их соответствующих моделей. Если пользователь делает что-то с B1view, который модифицирует B1model, а B1model в свою очередь модифицирует A1model, тогда A1model должен генерировать событие, которое получает A1view, и вызывает повторную визуализацию A1view и т.д. Это должно произойти как магия. (На практике это занимает некоторое время, чтобы получить магию, но я нашел, что Backbone будет очень мощным. А BackboneRelational помогает в таких вещах, как то, что вы описываете здесь.)

Ответ 3

Вышеупомянутое решение находится на правильном пути, но имеет некоторые проблемы.

initialize: function(){
  this.viewB = new ViewB();
  this.viewB.parentView = this;
  $(this.el).append(this.viewB.el);    
}

В основном, модель toJSON() теперь возвращает устаревшие данные. Я опубликовал решение для устранения этой проблемы в backbone.js плагине. Вы можете использовать его.

Ответ 4

Вы можете использовать некоторые расширения, Backbone-Forms https://github.com/powmedia/backbone-forms, например. Чтобы следовать вашему варианту использования, определите схему, например:

var ModelB = Backbone.Model.extend({
    schema: {
        attributeB1: 'Text',
        attributeB2: 'Text'
    }
});

var ModelC = Backbone.Model.extend({
    schema: {
        attributeC: 'Text',
    }
});

var ModelA = Backbone.Model.extend({
    schema: {
        attributeA1: 'Text',
        attributeA2: 'Text',
        refToModelB: { type: 'NestedModel', model: ModelB, template: 'templateB' },
        refToModelC: { type: 'NestedModel', model: ModelC, template: 'templateC' }
    }
});

Посмотрите https://github.com/powmedia/backbone-forms#customising-templates для частичных шаблонов.

Важными частями здесь являются type: 'NestedModel' и template: 'templateXXX'.

Этот плагин имеет некоторые ограничения, но вы можете смотреть на других в https://github.com/documentcloud/backbone/wiki/Extensions%2C-Plugins%2C-Resources.

Ответ 5

Существует базовый плагин Backbone-relational.js, который обеспечивает отношения один к одному, один-ко-многим и многие-к-одному между моделями для Backbone.

Я думаю, что этот js выполнит ваши потребности. Vist BackboneRelational для дополнительной документации.