javascript - Durandal构造函数但仍想记住数据

标签 javascript durandal durandal-2.0

假设我有以下 durandal 代码:

define(['durandal/app', 'plugins/http'], function (app) {
    var vm = function(){
        var self = this;
        self.myData = ko.observableArray([]);
        }

    };
    vm.activate = function() {
        this.myData([]);
    };
    vm.deactivate = function(){

    };
    return vm;
};

我知道通过返回构造函数,每次激活 View 模型时,它都会 返回一个新实例。

我的问题是:无论如何,当我访问时,如果之前访问中有 myData() ,那么我不想设置 this.myData([]); 但要使用之前的 myData()

我知道通过返回一个单例对象可以做到这一点,但是如果我想保留构造函数,我可以这样做吗?

另一个问题,如果您要获取新实例,从而保证“干净”的对象,那么在上面的代码中激活和停用有什么意义?

最佳答案

您可以采取多种方法,我在下面列举了这些方法。

对于下面的所有示例,请考虑选择“项目”主题。

注入(inject)(无 View )

通过这种方法,我们将 ProjectsServices 模块(单例)注入(inject)到 Projects 模块(实例)中。但只有当 ProjectsServices 不提供一个或多个 View 时,这种方法才有效。下面,我将向您展示如果我们的服务模块本身也提供一个或多个 View ,我们可以做什么。

ProjectsServices ViewModel(单例) servicesProjects.js

define('projectsServices', [],
    function() {
        var myData = null; //this may or may not be an observable

        return {
            myData: myData  //we return an object literal, which is what makes this module a singleton
        };
    }
);

项目 ViewModel(实例) projects.js

define('projects', ['projectsServices'],
    function(services) {

        //Constructor
        var Projects = function () {
            this.myData = ko.observable(); //this may or may not be an observable
        };

        Projects.prototype.activate = function (activationData) {
           this.myData(services.myData);
        };

        Projects.prototype.detached = function () {
            services.myData = this.myData();  /store back to the services module for later use
        };

        return Projects; //we return a constructor function, which is what makes this module an instance
    }
);

主机-客户端(查看)

通过这种方法,Projects 模块由 ProjectsServices 模块内部组成,并且我们通过 activationData 上的可观察对象来回传递 myData。此外,这种方法假设服务模块不仅提供代码服务,还提供 View 服务。弹出在其他表单之上的全局“添加联系人”表单是基于 View 的服务模块的示例。当然,“添加联系人” View 后面会有一个 viewModel,它代表用于添加联系人的代码服务。

ProjectsServices ViewModel(单例) servicesProjects.js

define('projectsServices', [],
    function() {
        var myData = ko.observable(); //should be an observable            
    }
);

项目服务 View servicesProjects.html

/*We bring in the Projects module through composition and pass in the observable, `myData`, itself (not `myData()`, but `myData`)*/
<div>
    <div data-bind="compose: {model: 'viewmodels/projects', activationData: myData}">
    </div>
</div>

项目 ViewModel(实例) projects.js

define('projects', [],
    function() {

        //Constructor
        var Projects = function () {
            this.myDataLocal = ko.observable(); //this may or may not be an observable
            this.myDataFromServices = null;
        };

        Projects.prototype.activate = function (activationData) {
            this.myDataFromServices = activationData
            this.myDataLocal(activationData());
        };

        Projects.prototype.detached = function () {
            this.myDataFromServices(this.myDataLocal());  /store back to the services module for later use
        };

        return Projects; //we return a constructor function, which is what makes this module an instance
    }
);

项目 View projects.html

/*There are infinite number of ways to bind to your myDataLocal*/
<div>
    <div data-bind="text: myDataLocal}">
    </div>
</div>

发布-订阅

通过这种方法,我们通过 app 利用 Durandal 的内置发布/订阅功能。这种方法可以与上面给出的注入(inject)或主机客户端一起使用。该策略是从实例模块的 activate 处理程序发布请求消息,并在同一处理程序内接收回复消息,这两个消息的目的是请求和提供 myData(大概是之前保存的)。当我们准备好将 myData 保存回服务模块时,我们会发送另一条以 myData 作为负载的消息。

ProjectsServices ViewModel(单例) servicesProjects.js

define('projectsServices', ['durandal/app'],
    function(app) {
        var 
            myData = null, //this may or may not be an observable

            activate = function () {
                app.on('requestForMyData').then( function () {
                    app.trigger('responseMyData', myData);
                });
                app.on('storeMyData').then( function (data) {
                    myData = data; //where 'data' is the payload
                });
            },

            detached = function () {
                app.off('requestForMyData');
                app.off('storeMyData');
            };

        return {
            myData: myData,  //we return an object literal, which is what makes this module a singleton
            activate: activate,
            detached: detached
        };
    }
);

项目 ViewModel(实例) projects.js

define('projects', ['durandal/app'],
    function(app) {

        //Constructor
        var Projects = function () {
            this.myData = ko.observable(); //this may or may not be an observable
        };

        Projects.prototype.activate = function () {
            var that = this;
            app.on('responseMyData').then( function (data) {
                that.myData(data);
            });
            app.trigger('requestForMyData'); //no payload
        };

        Projects.prototype.detached = function () {
            app.trigger('storeMyData', this.myData());
            app.off('responseMyData');
        };

        return Projects; //we return a constructor function, which is what makes this module an instance
    }
);

在这种情况下, View 不会改变,因此此处未提供它们。

消息总线

这种方法实际上与发布-订阅方法相同,只是我们使用的是客户端消息总线,例如 postal.js。正如您将看到的,它更加精致。这也恰好是我们在生产中采用的方法。这种方法应该与上面的主机-客户端方法一起使用,只是我们只是传递消息 channel ,而不是数据本身。

  • 您可以下载postal.js here .
  • 查看我 (@estaylorco) 在 Github 上与 Jim Cowart (@ifandelse) 的交流 here , here ,和 here .
  • 查看 RC postal.request-response (我在下面使用它,因为它是预览版),以及我在那里的交流。 postal.request-response 是我要求的(双向 channel ),它仅适用于您正在使用的场景。它极大地简化了请求-响应场景。

ProjectsServices ViewModel(单例) servicesProjects.js

define('projectsServices', ['postal'],
    function(postal) {
        var 
            outletMessageChannel = 'someuniqueidentifier',
            subscriptions = [],
            myData = null, //this may or may not be an observable

            activate = function () {
                var that = this;
                subscriptions.push(postal.subscribe({
                  channel: outletMessageChannel,
                  topic: 'request.mydata',
                  callback: function () {
                     postal.publish({
                         channel: outletMessageChannel,
                         topic: 'response.mydata',
                         data: that.myData
                     });
                  }
                }));
                subscriptions.push(postal.subscribe({
                  channel: outletMessageChannel,
                  topic: 'store.mydata',
                  callback: function (data) {
                      that.myData = data;   
                  }
                }));
            },

            detached = function () {
                //I'm using underscore.js here, but you can use any approach to iterate over subscriptions
                _.each(subscriptions, function(sub) {
                    sub.unsubscribe();
                    sub.callback = null;
                    sub = null;
                });
                subscriptions = null;
            };

        return {
            myData: myData,  //we return an object literal, which is what makes this module a singleton
            activate: activate,
            detached: detached
        };
    }
);

项目服务 View servicesProjects.html

/*We bring in the Projects module through composition and pass in the message channel*/
<div>
    <div data-bind="compose: {model: 'viewmodels/projects', activationData: outletMessageChannel}">
    </div>
</div>

项目 ViewModel(实例) projects.js

define('projects', ['postal'],
    function(postal) {

        //Constructor
        var Projects = function () {
            this.subscriptions = [];
            this.outletMessageChannel = '';
            this.myData = ko.observable(); //this may or may not be an observable
        };

        Projects.prototype.activate = function (activationData) {
            this.outletMessageChannel = activationData;

            var that = this;

            subscriptions.push(postal.subscribe({
              channel: this.outletMessageChannel,
              topic: 'response.mydata',
              callback: function (data) {
                  that.myData(data);   
              }
            }));

            postal.publish({
                channel: this.outletMessageChannel,
                topic: 'request.mydata',
                data: null //no payload
            });              

        };

        Projects.prototype.detached = function () {
            postal.publish({
                channel: this.outletMessageChannel,
                topic: 'store.mydata',
                data: this.myData()
            }); 

            //I'm using underscore.js here, but you can use any approach to iterate over subscriptions
            _.each(this.subscriptions, function(sub) {
                sub.unsubscribe();
                sub.callback = null;
                sub = null;
            });
            this.subscriptions = null;
        };

        return Projects; //we return a constructor function, which is what makes this module an instance
    }
);

请注意,在这种情况下,“项目” View 不会更改,因此此处不包含它。

关于javascript - Durandal构造函数但仍想记住数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23573100/

相关文章:

javascript - JQuery - 分离然后将一个项目附加到列表中 - 为什么这个简单的示例不起作用?

javascript - 如何在外部站点中嵌入 hubspot 表单

javascript - 为什么 parseInt 无法在 Javascript 中正确测试数组?

mvvm - 使用 Twitter Bootstrap 按钮组作为带有 knockout 绑定(bind)的单选框

azure - Durandal SPA 使用构建部署命令中的优化器部署到 Azure 网站

javascript - 如何在 Durandal 中显示带有参数化路由的 "not found"页面

javascript - 如何从 "^pearl(pig|hog)+$"获取匹配的输出?

javascript - 了解两种 Javascript 语法之间的差异

javascript - DurandalJS 和使用参数组合 subview

javascript - 除非开发工具打开,否则 Bootstrap 模式不会在 IE11 中显示