durandaljs中的订阅活动未取消订阅

时间:2013-10-04 08:03:27

标签: durandal

这是应用程序的流程:

shell.js加载包含schoolyearbrowser.js的schoolyeardialog.js,它通过创建或编辑按钮加载schoolyearwizard.js。

当我多次重复这些步骤时:单击“创建/编辑”按钮,然后执行多次 在我的SchoolyearWizard中请求:

 $.when(service.editSchoolyear(schoolyearId))

原因是我认为订阅的活动没有正确取消订阅。

我在SchoolyearDialog.js文件中尝试了不同的取消订阅方式。

当我执行subscription.off()时,事件都没有触发。在app.on之后(...) 或者是在错误的位置取消订阅。

我应该在哪里正确取消订阅?

如果你们需要一个样本回购作为visual studio解决方案,我可以提供这个,如果它有帮助,或者你可以清楚地看到错误?!

当SchoolyearDialog模块被“卸载”时,我还考虑过从2个事件中取消订阅创建/编辑,因为这两个事件都可以/不会取消订阅创建或编辑订阅,就像我现在点击添加一样或编辑按钮......我该怎么做?

SHELL

define(['plugins/router', 'durandal/app', 'viewmodels/SchoolyearDialog', 'knockout'], function (router, app, schoolyearDialog, ko) {

    self.schoolyearIsLoaded = ko.observable(false);

    var saveTimeTableSubscription = app.on('savedTimeTable').then(function (options) {
         // after coming the 2nd time here
        if (!self.schoolyearIsLoaded()) {
            router.map([{ route: 'lessonplanner', moduleId: 'viewmodels/lessonplanner', title: 'lesson planner', nav: true },
                         { route: 'documentbrowser', moduleId: 'viewmodels/documentbrowser', title: 'document browser', nav: true }])
                 .buildNavigationModel();

            self.schoolyearIsLoaded(true);
        }

        router.navigate("lessonplanner", true);
    });


    return {
        router: router,
        activate: function () {
            router.map([{ route: '', moduleId: 'viewmodels/SchoolyearDialog', nav: true, title: 'Schoolyearbrowser' }
            ]).buildNavigationModel();
            return router.activate('SchoolyearDialog');

        }
    };
});

SchoolyearDialog

define(['durandal/app', 'knockout', 'plugins/router', 'viewmodels/SchoolyearWizard'],
    function (app, ko, router, wizard) {

        var ctor = function () {
            debugger;
            var self = this;
            self.createSubscribe = ko.observable();
            self.editSubscribe = ko.observable();

            self.activeScreen = ko.observable('viewmodels/SchoolyearBrowser'); // set the schoolyear browser as default module

            var createWizardSubscription = app.on('createWizard').then(function () {

                self.createSubscribe().off();
                self.createSubscribe(null);

                self.activeScreen(new wizard('create'));

            }, self);
            self.createSubscribe(createWizardSubscription);

            var editWizardSubscription = app.on('editWizard').then(function (schoolyearId) {

                self.editSubscribe().off();
                self.editSubscribe(null);

                self.activeScreen(new wizard('edit', schoolyearId));

            }, self);
            self.editSubscribe(editWizardSubscription);
        }
        return ctor;
    });

SchoolyearBrowser

define(['durandal/app', 'plugins/dialog', 'knockout', 'services/dataservice', 'plugins/router'],
    function (app, dialog, ko, dataservice, router) {
        var SchoolyearBrowser = function () {

            var self = this;
            self.schoolyears = ko.observableArray();

            $.when(dataservice.getSchoolyears())
             .done(function (schoolyearModels) {
                 self.schoolyears(schoolyearModels);
             });

            self.create = function () {
                app.trigger('createWizard');
            }

            self.edit = function () {
                app.trigger('editWizard', 1);
            }
        };

        return SchoolyearBrowser;
    });

SchoolyearWizard

define(['durandal/activator', 'viewmodels/step1', 'viewmodels/step2', 'knockout', 'durandal/app', 'services/dataservice', 'viewmodels/CreateEditSchoolyearViewModel'],
    function (activator, Step1, Step2, ko, app, service, CreateEditSchoolyearViewModel) {

        var ctor = function (viewMode, schoolyearId) {
            debugger;
            // depending on the mode I could setup 2 different step modules for create and edit ? and the Wizard has one property called content
            if (viewMode === 'edit') {

                $.when(service.editSchoolyear(schoolyearId))
                 .done(function (response) {
                     debugger;
                     self.viewModel(new CreateEditSchoolyearViewModel(response));
                 }).fail(function (error) {
                     alert(error);
                 });
            }
            else if (viewMode === 'create') {

                $.when(service.createSchoolyear())
                 .done(function (response) {
                     debugger;
                     self.viewModel(new CreateEditSchoolyearViewModel(response));
                 }).fail(function (error) {
                     alert(error);
                 });
            }

            var self = this;
            var steps = [new Step1(viewMode), new Step2(viewMode)];
            var step = ko.observable(0);   // Start with first step
            self.activeStep = activator.create();
            var stepsLength = steps.length;

            self.viewModel = ko.observable();

            this.hasPrevious = ko.computed(function () {
                return step() > 0;
            });

            self.caption = ko.observable();
            this.activeStep(steps[step()]);

            this.hasNext = ko.computed(function () {
                if ((step() === stepsLength - 1) && self.activeStep().isValid()) {
                    // save
                    self.caption('save');
                    return true;
                } else if ((step() < stepsLength - 1) && self.activeStep().isValid()) {
                    self.caption('next');
                    return true;
                }
            });

            this.isLastStep = function () {
                return step() === stepsLength - 1;
            }

            this.next = function () {
                if (this.isLastStep()) {

                    var vm = this.activeStep(); //.viewModel;

                    $.when(service.saveCreateSchoolyear({ schoolyearId: 1 })).done(function () {

                        app.trigger('savedTimeTable', { isSuccess: true });
                    }).fail(function (e) {

                        alert(e);
                    });

                }
                else if (step() < stepsLength) {
                    step(step() + 1);
                    self.activeStep(steps[step()]);
                }
            }

            this.previous = function () {
                if (step() > 0) {
                    step(step() - 1);
                    self.activeStep(steps[step()]);
                }
            }
        }
        return ctor;
    });

2 个答案:

答案 0 :(得分:0)

这对我帮助很大:

activator.deactivate函数允许前一个对象执行自定义停用逻辑。“

SchoolyearDialog.js

self.deactivate = function () {
                 self.createSubscribe().off();
                self.editSubscribe().off();
}

当停用schoolyearDialog时,两个事件都会取消订阅,单击按钮创建/编辑。这对我来说是一个干净的解决方案:)

答案 1 :(得分:0)

我同意您的解决方案,但我建议不要使用没有参数的普通 .off(),因为这会导致取消注册应用程序中的所有事件。

而是将事件名称作为参数传递给off方法:

self.createSubscribe().off('savedTimeTable');