1

This is the flow of the application:

The shell.js loads the schoolyeardialog.js which contains the schoolyearbrowser.js which loads the schoolyearwizard.js via create or edit button.

When I repeat these steps multiple times: click create/edit button then I do multiple requests in my SchoolyearWizard to this:

 $.when(service.editSchoolyear(schoolyearId))

The reason is that the subscribed events are not correctly unsubscribed in my opinion.

I have tried different ways of unsubscribing in the SchoolyearDialog.js file.

Either the events did not fire - when I did the subscription.off(); after the app.on(...) or It was unsubscribed at the wrong position.

Where should I unsubscribe correctly?

If you guys need a sample repo as visual studio solution I can provide this if it helps or maybe you see clearly and immediately the error?!

I have also thought about unsubscribing from the 2 events create/edit when the SchoolyearDialog module is "unloaded" because then both events could/would be unsubscribed not only the create OR edit subscription as it is now when I either click the add or edit button... how would I do that?

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

2 回答 2

0

这对我帮助很大:

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

SchoolyearDialog.js

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

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

于 2013-10-04T16:18:18.193 回答
0

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

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

self.createSubscribe().off('savedTimeTable');
于 2016-11-18T11:36:47.110 回答