在 requirejs 中设置一个 Backbone 循环依赖的集合模型
Set a Backbone collection model with circular dependencies in requirejs
问题是我在一些 Backbone 模块之间存在循环依赖,所以我必须使用 "exports" 作为 Requirejs 在其文档 http://requirejs.org/docs/api.html#circular 中指定的规范。所以模型 'A' 将如下所示:
define(function(require, exports) {
var B = require('B');
var A = Backbone.Model.extend({
});
exports.model = A;
});
集合 'B' 是这样的:
define(function(require, exports) {
var A = require('A');
var B = Backbone.Model.extend({
model: A.model
});
exports.model = B;
});
这里的问题是,当我必须指定集合 'B' 模型 属性 时,模型 'A' 尚未定义。这是我在尝试使用这样的模型设置集合时遇到的错误:
B.collection.set([{id: 1}, {id: 2}]);
Uncaught TypeError: 'undefined' is not an object (evaluating 'targetModel.prototype') (http://127.0.0.1:9999/bower_components/backbone/backbone.js:689)
关于如何解决这个问题有什么想法吗?
从示例中,不清楚 B
实际上取决于 A
。如果它只是一个 model:collection 关系,则删除模型对其集合的依赖性可能是有意义的。如果完全有可能打破循环依赖,我强烈建议您这样做。
不过,如果确实需要反向引用,一个选择可能是将资源移动到同一个模块中并进行一种惰性导出:
define(function() {
var lazyThings = {
A: null,
B: null
};
lazyThings.A = Backbone.Model.extend({
collection: things.B
});
lazyThings.B = Backbone.Collection.extend({
model: A
});
return lazyThings;
});
或者,您可以 return lazyThings.B
然后从其原型访问模型:
require('b', function (B) {
var A = B.prototype.model; // A
});
最后,可以通过延迟调用相应的依赖项(即,在解析模块之后)来使 requirejs 工作:
// B
define(['a'], function (A) {
return function () {
return Backbone.Collection.extend({
model: A()
});
}
});
// A
define(['b'], function (B) {
return function () {
return Backbone.Model.extend({
model: B()
});
}
});
以下适合我,尽量说清楚。
你有一个模型,你有一个collection。为了使它们相互依赖并避免循环依赖,您需要第三个 "mediator" 依赖。在 Backbone 中拥有一个模型并轻松查找它属于什么 collection 很方便,反之亦然,但问题当然是它们具有循环依赖性。
所以之前我们有:
+model
+collection
__________
= circular
及之后:
+model
+collection
+mediator
________
= OK
//collection
define([
'@allModels',
'@BaseCollection',
'@AppDispatcher',
'@allFluxConstants',
'app/js/flux/flux-helpers/collectionUpdater'
],
function (allModels, BaseCollection, AppDispatcher, allFluxConstants, collUpdater) {
var dispatchCallback = function (payload) {
return true;
};
var BaymaxComponentCollection = BaseCollection.extend({
model: allModels['BaymaxComponent'],
collectionName:'baymax-component',
url: '/baymax_component',
batchURL: '/batch/baymax_component',
initialize: function (models, opts) {
this.dispatchToken = AppDispatcher.register(dispatchCallback);
},
// collection is sorted by original insertion order.
comparator: 'order'
});
return new BaymaxComponentCollection();
});
//型号
define([
'@BaseModel',
'@ModelCollectionMediator',
'@AppDispatcher'
],
function ( BaseModel, MCM) {
var BaymaxComponent = BaseModel.extend({
idAttribute: 'id',
urlRoot: '/baymax_component',
collectionName: 'baymax-component',
defaults: function () { //prevents copying default attributes to all instances of UserModel
return {}
},
initialize: function (attributes, opts) {
//*** the following line is crucial ***
this.collection = MCM.findCollectionByName(this.collectionName);
},
validate: function (attr) {
return undefined;
}
},
{ //class properties
});
return BaymaxComponent;
});
//调解员
define(function (require) {
return {
findCollectionByName: function (name) {
var allCollections = require('@allCollections');
return allCollections[name];
}
};
});
问题是我在一些 Backbone 模块之间存在循环依赖,所以我必须使用 "exports" 作为 Requirejs 在其文档 http://requirejs.org/docs/api.html#circular 中指定的规范。所以模型 'A' 将如下所示:
define(function(require, exports) {
var B = require('B');
var A = Backbone.Model.extend({
});
exports.model = A;
});
集合 'B' 是这样的:
define(function(require, exports) {
var A = require('A');
var B = Backbone.Model.extend({
model: A.model
});
exports.model = B;
});
这里的问题是,当我必须指定集合 'B' 模型 属性 时,模型 'A' 尚未定义。这是我在尝试使用这样的模型设置集合时遇到的错误:
B.collection.set([{id: 1}, {id: 2}]);
Uncaught TypeError: 'undefined' is not an object (evaluating 'targetModel.prototype') (http://127.0.0.1:9999/bower_components/backbone/backbone.js:689)
关于如何解决这个问题有什么想法吗?
从示例中,不清楚 B
实际上取决于 A
。如果它只是一个 model:collection 关系,则删除模型对其集合的依赖性可能是有意义的。如果完全有可能打破循环依赖,我强烈建议您这样做。
不过,如果确实需要反向引用,一个选择可能是将资源移动到同一个模块中并进行一种惰性导出:
define(function() {
var lazyThings = {
A: null,
B: null
};
lazyThings.A = Backbone.Model.extend({
collection: things.B
});
lazyThings.B = Backbone.Collection.extend({
model: A
});
return lazyThings;
});
或者,您可以 return lazyThings.B
然后从其原型访问模型:
require('b', function (B) {
var A = B.prototype.model; // A
});
最后,可以通过延迟调用相应的依赖项(即,在解析模块之后)来使 requirejs 工作:
// B
define(['a'], function (A) {
return function () {
return Backbone.Collection.extend({
model: A()
});
}
});
// A
define(['b'], function (B) {
return function () {
return Backbone.Model.extend({
model: B()
});
}
});
以下适合我,尽量说清楚。
你有一个模型,你有一个collection。为了使它们相互依赖并避免循环依赖,您需要第三个 "mediator" 依赖。在 Backbone 中拥有一个模型并轻松查找它属于什么 collection 很方便,反之亦然,但问题当然是它们具有循环依赖性。
所以之前我们有:
+model
+collection
__________
= circular
及之后:
+model
+collection
+mediator
________
= OK
//collection
define([
'@allModels',
'@BaseCollection',
'@AppDispatcher',
'@allFluxConstants',
'app/js/flux/flux-helpers/collectionUpdater'
],
function (allModels, BaseCollection, AppDispatcher, allFluxConstants, collUpdater) {
var dispatchCallback = function (payload) {
return true;
};
var BaymaxComponentCollection = BaseCollection.extend({
model: allModels['BaymaxComponent'],
collectionName:'baymax-component',
url: '/baymax_component',
batchURL: '/batch/baymax_component',
initialize: function (models, opts) {
this.dispatchToken = AppDispatcher.register(dispatchCallback);
},
// collection is sorted by original insertion order.
comparator: 'order'
});
return new BaymaxComponentCollection();
});
//型号
define([
'@BaseModel',
'@ModelCollectionMediator',
'@AppDispatcher'
],
function ( BaseModel, MCM) {
var BaymaxComponent = BaseModel.extend({
idAttribute: 'id',
urlRoot: '/baymax_component',
collectionName: 'baymax-component',
defaults: function () { //prevents copying default attributes to all instances of UserModel
return {}
},
initialize: function (attributes, opts) {
//*** the following line is crucial ***
this.collection = MCM.findCollectionByName(this.collectionName);
},
validate: function (attr) {
return undefined;
}
},
{ //class properties
});
return BaymaxComponent;
});
//调解员
define(function (require) {
return {
findCollectionByName: function (name) {
var allCollections = require('@allCollections');
return allCollections[name];
}
};
});