Создание вложенных моделей с 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;
});
Покойный для этого сейчас, но надеюсь, что это поможет другим.