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

Я новичок в BackboneJS, и я застрял с вложенными отношениями, используя модель Backbone-relational с 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)

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


person user1305990    schedule 01.04.2012    source источник
comment
Подобно stackoverflow. com/questions/9225640/   -  person Daniel Eggert    schedule 17.04.2012


Ответы (4)


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

http://jsfiddle.net/yNLbq

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

http://jsfiddle.net/jDw5e

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

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

person jp10k    schedule 09.05.2012

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

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

Ваша самая сложная проблема заключается в том, что relatedModel ModuleModel на самом деле является самим 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);
      });
    });

});
person Chris Camaratta    schedule 09.06.2013

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

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

в 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;
});
person dokkaebi    schedule 08.06.2012
comment
экспорт — это не то, что вы определяете; это специально лечится require. Requirejs создает словарь и передает его любым определениям, требующим «экспорта», чтобы вы могли обмениваться значениями между вызовами определения. Вам не нужно создавать файл или делать что-то особенное — просто используйте волшебное имя «экспорт» в качестве одной из ваших зависимостей. - person dokkaebi; 27.06.2012
comment
Пожалуйста, не могли бы вы сказать мне, какой модуль я должен создать? оба или только один, а если только один, то какой между ModuleCollection и ModuleModel? - person Lorraine Bernard; 27.06.2012
comment
Используя код, который я разместил, и ModuleModel, и ModuleCollection должны работать должным образом. В другом месте вашего кода вы можете сделать что-то вроде require(['ModuleCollection', 'ModuleModel'], function(ModuleCollection, ModuleModel) { myModules = new ModuleCollection(); myModel = new ModuleModel({ /* some values */ }); myModules.add(myModel); }. Это может помочь увидеть, что вы пытаетесь сделать - если это не работает должным образом, вы можете открыть новый вопрос и дать ссылку на него здесь. - person dokkaebi; 27.06.2012

Некоторое время назад я столкнулся с той же проблемой и следовал подходу, использованному Эндрю Ферком для его вопроса: -реляционные подмодели с помощью RequireJS. Проблема возникает из-за того, что вы определяете модели как модули Require, поэтому они не существуют в глобальной области видимости, где их может искать магистрально-реляционная модель. Вместо того, чтобы использовать глобальную область (превосходит цель Require) или экспортировать (немного сложно с отношениями), вы можете определить область для своих моделей и указать backbone-relational искать модели в ней с помощью 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;
}

Кстати, вы должны изменить свою зависимость от Backbone и не требовать для этого 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;
});

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

person Nemisha    schedule 19.04.2014