Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Durandal router / lifecycle events when using a childRouter

In a single page app built using Durandal, I have a settings view, with different sections. I use a childRouter to resolve the different sections.

In this application, a lot of code hooks into the composition lifecycle events that Durandal uses. For example, this custom binding:

ko.bindingHandlers.autoFocus = {
    init: function (element) {
        var $element = $(element),
            setFocus = function () {
                $element.focus();
            };

        router.on('router:navigation:composition-complete', setFocus);
        ko.utils.domNodeDisposal.addDisposeCallback(element, function () {
            router.off('router:navigation:composition-complete', setFocus);
            $element = null;
        });
    }
};

This custom binding has functioned perfectly so far, setting focus to the field the binding was applied to when the view is displayed.

However, with the child router, the timing is off. It seems that the main router triggers the 'router:navigation:composition-complete' event when the 'settings' view is loaded. At this point, the child view is not yet displayed, and the element with the autofocus binding does not get the focus. This is illustrated even more clearly when navigating between settings pages: on leaving a page, the field with the autofocus binding on the old child view gets the focus, then the new child view is displayed without a focused element.

Is there any way to get the child router to omit events as well? Or possibly to get the main router to postpone the events till the child router is done?

I've also read that this applies in other stages of composition as well: e.g. the deactivate callback will not be called on the viewmodel of a child view. So a general fix for event triggering on child routers would be the ideal solution I'm looking for.

Thanks in advance.

like image 265
Hans Roerdinkholder Avatar asked Jan 29 '14 14:01

Hans Roerdinkholder


1 Answers

Try this:

ko.bindingHandlers.autoFocus = {
    init: function (element) {
        var $element = $(element),
            setFocus = function (child, parent, context) {
                $element.focus();
                        if (child.router)
                            child.router.on('router:navigation:composition-complete', function () {    $element.focus(); });
};
        router.on('router:navigation:composition-complete', setFocus);
        ko.utils.domNodeDisposal.addDisposeCallback(element, function () {
            router.off('router:navigation:composition-complete', setFocus);
            $element = null;
        });
    }
};
like image 50
Adel Sal Avatar answered Sep 19 '22 21:09

Adel Sal