Инициализировать модели магистрали на основе другой модели магистрали

У меня есть config.json, который я собираюсь загрузить в свое приложение в качестве базовой модели, например:

var Config = Backbone.Model.extend({
    defaults: {
        base: ''
    },
    url: 'config.json'
});

Другие модели должны зависеть от некоторых данных, содержащихся в Config, например:

var ModelA = Backbone.Collection.extend({
    initialize: function(){
        //this.url should be set to Config.base + '/someEndpoint';
    }
});

В приведенном выше примере свойство url элемента ModelA зависит от значения свойства base элемента Config.

Как правильно настроить это в приложении Backbone?


person lbrahim    schedule 06.08.2015    source источник
comment
Один из способов — переопределить Backbone.sync.   -  person hindmost    schedule 06.08.2015
comment
@hindmost Был бы признателен за простой пример кода. Я новичок в Backbone. Спасибо.   -  person lbrahim    schedule 06.08.2015
comment
Здесь не может быть простых образцов. Однако я предлагаю взглянуть на моё JS-приложение, где переопределение Backbone.sync используется для задач, аналогичных вашим.   -  person hindmost    schedule 06.08.2015
comment
@hindmost очень мило, Ибрагим, это твой ответ. В качестве альтернативы вы можете использовать backbone-associations или backbone-relational, чтобы сделать то же самое в более общем плане. Но стратегия хорошая — он говорит, если отсутствуют зависимости, вернуть false из sync, а иначе составить из них.   -  person tacos_tacos_tacos    schedule 07.08.2015
comment
@tacos_tacos_tacos Если я использую, например, backbone-associations, то я просто создам связь 1:1 между Config и ModelA, и при выборке для ModelA Config также будет получен и доступен для ModelA?   -  person lbrahim    schedule 07.08.2015


Ответы (1)


Как я понимаю, ваши основные вопросы таковы:

  • Как мы получим экземпляр модели конфигурации?
  • Как мы будем использовать модель конфигурации для установки url зависимой модели?
  • Как мы можем убедиться, что мы не используем функцию url в зависимой модели слишком рано?

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

Я думаю, что лучший способ справиться с первой проблемой — сделать эту модель конфигурации одноэлементной. Я предоставлю код из backbone-singleton Страница GitHub ниже, но я не хочу, чтобы ответ был длинным по вертикали, пока я не закончу объяснение, поэтому читайте дальше...

var MakeBackboneSingleton = function (BackboneClass, options) { ... }

Затем мы создаем одноэлементное свойство AppConfiguration, а также свойство deferred, используя преимущество jQuery. Результат fetch даст always(callback), done(callback) и т. д.

var AppConfiguration = MakeBackboneSingleton(Backbone.Model.extend({
    defaults: {
        base: null
    },
    initialize: function() {
        this.deferred = this.fetch();
    },
    url: function() {
        return 'config.json'
    }
}));

Теперь пришло время определить зависимую модель DependentModel, похожую на вашу. Он вызовет AppConfiguration(), чтобы получить экземпляр.

Обратите внимание, что из-за MakeBackboneSingleton следует все true:

var instance1 = AppConfiguration();
var instance2 = new AppConfiguration();
instance1 === instance2; // true
instance1 === AppConfiguration() // true

Модель будет автоматически fetch при предоставлении id, но только после завершения выборки AppConfiguration. Обратите внимание, что вы можете использовать always, then, done и т. д.

var DependentModel = Backbone.Model.extend({
    initialize: function() {
        AppConfiguration().deferred.then(function() {
            if (this.id)
                this.fetch();
        });
    },
    url: function() {
        return AppConfiguration().get('base') + '/someEndpoint';
    }
});

Теперь, наконец, собрав все это воедино, вы можете создавать экземпляры некоторых моделей.

var newModel = new DependentModel();   // no id => no fetch

var existingModel = new DependentModel({id: 15}); // id => fetch AFTER we have an AppConfiguration

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

Вот вам MakeBackboneSingleton (опять же из репозитория GitHub):

var MakeBackboneSingleton = function (BackboneClass, options) {
    options || (options = {});

    // Helper to check for arguments. Throws an error if passed in.
    var checkArguments = function (args) {
        if (args.length) {
            throw new Error('cannot pass arguments into an already instantiated singleton');
        }
    };

    // Wrapper around the class. Allows us to call new without generating an error.
    var WrappedClass = function() {
        if (!BackboneClass.instance) {
            // Proxy class that allows us to pass through all arguments on singleton instantiation.
            var F = function (args) {
                return BackboneClass.apply(this, args);
            };

            // Extend the given Backbone class with a function that sets the instance for future use.
            BackboneClass = BackboneClass.extend({
                __setInstance: function () {
                    BackboneClass.instance = this;
                }
            });

            // Connect the proxy class to its counterpart class.
            F.prototype = BackboneClass.prototype;

            // Instantiate the proxy, passing through any arguments, then store the instance.
            (new F(arguments.length ? arguments : options.arguments)).__setInstance();
        }
        else {
            // Make sure we're not trying to instantiate it with arguments again.
            checkArguments(arguments);
        }

        return BackboneClass.instance;
    };

    // Immediately instantiate the class.
    if (options.instantiate) {
        var instance = WrappedClass.apply(WrappedClass, options.arguments);

        // Return the instantiated class wrapped in a function so we can call it with new without generating an error.
        return function () {
            checkArguments(arguments);

            return instance;
        };
    }
    else {
        return WrappedClass;
    }
};
person tacos_tacos_tacos    schedule 06.08.2015
comment
Нет ли здесь элегантного решения? FTR, это в настоящее время, как я делаю. Передача config после загрузки через конструкторы моделей. - person lbrahim; 07.08.2015
comment
Более гладкие способы будут включать переопределение fetch или sync или save или delete напрямую. - person tacos_tacos_tacos; 07.08.2015
comment
Если хотите, я могу попытаться показать вам, как это сделать. - person tacos_tacos_tacos; 07.08.2015
comment
Если это не проблема, образцы кода всегда полезны. - person lbrahim; 07.08.2015