基于另一个 Backbone 个模型初始化 Backbone 个模型

Initialize Backbone Models based on another Backbone Model

我有一个 config.json 将作为 Backbone 模型加载到我的应用程序中,例如:

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';
    }
});

在上面的示例中,ModelAurl 属性 取决于 Configbase 属性 的值。

如何在 Backbone 应用程序中正确设置它?

据我所知,您的基本问题是:

  • 我们将如何获得配置模型的实例?
  • 我们将如何使用配置模型来设置依赖模型的url
  • 我们如何确保我们不会过早地在依赖模型上使用 url 函数?

有很多方法可以解决这个问题,但我会提出一些具体建议,这样我就可以提供指导和代码,"get it done," 可以这么说。

我认为处理第一个问题的最佳方法是使该配置模型成为单例。我将在下面的 backbone-singleton GitHub 页面提供代码,但我不希望答案在垂直方向上很长,直到我完成解释,所以请继续阅读...

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

接下来,我们利用 jQuery 创建一个单例 AppConfiguration 和一个 deferred 属性。 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

模型将在提供 id 时自动 fetch,但仅在 我们完成 AppConfiguration 的提取后 。请注意,您可以使用 alwaysthendone

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;
    }
};