Создание вложенных моделей с backboneJS + backbone-relational + requireJS

Я новичок в BackboneJS, и я застрял с вложенными отношениями, используя Backbone-реляционную модель с RequireJS. Думаю, что я столкнулся с круговыми проблемами. Любая помощь будет высоко оценена!

У меня есть следующая модель и коллекция:

 /* Module Model at models/module*/
define([
'jquery', 
'underscore', 
'backbone',
'backboneRelational',
], function($, _, Backbone) {

    var ModuleModel = Backbone.RelationalModel.extend({

        urlRoot: 'api/module',
        _radius: 50,
        relations: [{
            type: Backbone.HasMany,
            key: 'children',
            relatedModel: 'ModuleModel',
            collectionType: 'ModuleCollection',
            reverseRelation: {
                key: 'parent_id',
                includeInJSON: 'id' 
            }
        }],
        url: function() {
            return this.id? 'api/module/' + this.id : 'api/module';
        }
    });
    return ModuleModel;
});

/* Module Collection */
define([
'jquery',
'underscore', 
'backbone', 
'models/module'
], function($, _, Backbone, ModuleModel) {

    var ModuleCollection = Backbone.Collection.extend({

        model: ModuleModel,
        url: 'api/modules'
    });

    return ModuleCollection;
});

Когда я инициализирую объект ModuleModel, он выдает следующую ошибку:

Relation=child; no model, key or relatedModel (function (){ parent.apply(this, arguments); }, "children", undefined)

Не могли бы вы указать мне в правильном направлении?

Ответ 1

Это выглядит как проблема. Во время инициализации ModuleModel он хочет создать отношение hasMany с самим собой, но он не может найти себя, и это даст вам горе в виде указанной ошибки:

http://jsfiddle.net/yNLbq

Как только объект достигнут из текущей области, все начинает работать:

http://jsfiddle.net/jDw5e

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

Надеюсь, что это поможет.

Ответ 2

Я столкнулся с этой проблемой: RequireJS + BackboneRelational + Self-Referential. Кажется, он унаследовал некоторые из своих проблем из этой темы, поэтому я подумал, что могу добавить свой копейки.

Во-первых, поскольку вы используете RequireJS, глобальных переменных нет. Вы не можете просто указать имя объекта, вам нужно предоставить фактические ссылки на объекты для relatedModel и collectionType.

Самая сложная проблема заключается в том, что ModuleModel relatedModel на самом деле ModuleModel, который не будет определяться при назначении его relatedModel (с использованием модели AMD). Вы должны отложить назначение до тех пор, пока не будет назначен ModuleModel.

Наконец, вам нужно решить круговую ссылку. dokkaebi находится на правильном пути, когда он предлагает использовать exports, но его реализация фактически злоупотребляет exports. При экспорте присоединяйте объект непосредственно к exports, как он предлагает, но когда вы его импортируете, вам нужно обратиться к модулю, чтобы использовать его, а не exports.

Это должно работать:

ModuleModel.js

define(['exports', 'ModuleCollection'], function (exports, Module) {
    'use strict';

    var ModuleModel = Backbone.RelationalModel.extend({
        urlRoot: 'api/module',
        _radius: 50,
        relations: [{
            type: Backbone.HasMany,
            key: 'children',
            // ModuleModel is undefined; this line is useless
            // relatedModel: ModuleModel,
            // no globals in require; must use imported obj ref
            collectionType: Module.Collection,
            reverseRelation: {
                key: 'parent_id',
                includeInJSON: 'id' 
            }
        }],
        url: function() {
            return this.id? 'api/module/' + this.id : 'api/module';
        }
    });

    // Now that `ModuleModel` is defined, we can supply a valid object reference:
    ModuleModel.prototype.relations[0].relatedModel = ModuleModel;

    // Attach `Model` to `exports` so an obj ref can be obtained elsewhere
    exports.Model = ModuleModel;
});

ModuleCollection.js

define(['exports', 'ModuleModel'], function(exports, Module) {
    'use strict';

    var ModuleCollection = Backbone.Collection.extend({
        // must reference the imported Model
        model: Module.Model,
        url: 'data.php' // <-- or wherever
    });

    // Attach `Collection` to `exports` so an obj ref can be obtained elsewhere
    exports.Collection = ModuleCollection;
});

Main.js

define(['ModuleCollection'], function(Module) {
    'use strict';

    var modules = new Module.Collection();
    modules.fetch().done(function() {
      modules.each(function(model) {
        console.log(model);
      });
    });

});

Ответ 3

Из комментария в backbone-relational.js v0.5.0 (строка 375):
// 'export' должен быть глобальным объектом, где 'relatedModel' может быть найден, если задан как строка.

Если вам требуется специальное значение "export" в качестве зависимости в вашем вызове define, а затем поместите ваш модуль на объект экспорта, прежде чем вы вернетесь, вы можете ссылаться на этот модуль как на строку или в качестве члена экспорта.

в ModuleModel.js:

define(['exports', 'use!backbone', 'use!backbone-relational'], function(exports, Backbone) {
  var ModuleModel = Backbone.RelationalModel.extend({
    relations: [
      {
        type: Backbone.HasMany,
        key: 'groups',
        relatedModel: 'ModuleModel',
        collectionType: 'ModuleCollection'
      }
    ]
  });
  exports.ModuleModel = ModuleModel;
  return ModuleModel;
});

и в ModuleCollection.js:

define(['exports', 'use!backbone'], function(exports, Backbone) {
  var ModuleCollection = Backbone.RelationalModel.extend({
    url: '/api/v1/module/';
    model: exports.ModuleModel;
  });
  exports.ModuleCollection = ModuleCollection;
  return ModuleCollection;
});

Ответ 4

Я столкнулся с той же проблемой некоторое время назад и последовал подходу, используемым Эндрю Ферком для его вопроса: Backbone-реляционные подмодели с RequireJS. Проблема возникает из-за того, что вы определяете модели как требуемые модули, чтобы они не существовали в глобальной области, где базовая реляционная система может их искать. Вместо того, чтобы использовать глобальную область действия (превосходит цель Требовать) или экспортировать (бит сложный с отношениями), вы можете определить область для своих моделей и указать базовую реляционную структуру для поиска в ней моделей с помощью addModelScope().

//modelStore.js - A scope in which backbone-relational will search for models
//Defined separately so you can access 'modelStore' directly for your models instead of requiring 'app' every time.
define(['app'], function(app) {
    app.modelStore  = {};
    Backbone.Relational.store.addModelScope(app.modelStore);
    return app.modelStore;
}

Кстати, вы должны закрепить свою зависимость от базовой линии и не нужно требовать для нее jQuery и Underscore.

//ModuleModel (The ModuleModel module. Nice.)
define(['modelStore', 'backbone', 'backboneRelational'], function(modelStore, Backbone {
    modelStore.ModuleModel = Backbone.RelationalModel.extend({
        relations: [
        {
            type: Backbone.HasMany,
            key: 'groups',
            relatedModel: 'ModuleModel', //Not modelStore.ModuleModel
            collectionType: 'ModuleCollection'
        }
        ]
    });
    return modelStore.ModuleModel;
});

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