1

I am new to durandal and single page apps, I am having issues getting the deactivate and canDeactivate function to fire. I am using some custom code to achieve deep linking, which is probably what is causing my issue. I followed the example here: https://github.com/evanlarsen/DurandalDeepLinkingExample please also see Durandal Subrouting (Hottowel)

Any help would be most appreciated.

Here is the viewmodel code I am calling:

define([''], function () {

var vm = {
    activate: function () {
        alert('In activate!');
    },
    deactivate: function () {
        alert('In deactivate!');
    },
    canDeactivate: function () {
        alert('In candeactivate!');
    }
}
return vm;

});

Here is the viewhtml

<div class="container-fixed"> 
 <div>
    <header>
        <!-- ko compose: {view: 'Main/Users/UsersNav'} -->
        <!-- /ko-->
    </header>
    <section id="content" class="in-users">
        <!--ko compose: { 
                            model: inUsers, afterCompose: router.afterCompose,
                            transition: 'entrance', 
                            activate: true
                        } -->
        <!--/ko-->
    </section> 
 </div>
</div>

Here is the calling code:

define(['durandal/system', 'durandal/viewModel', 'durandal/plugins/router'],
function (system, viewModel, router) {
    var App = {
        router: router,
        activate: activate,
        showPage: showPage,
        isPageActive: isPageActive,
        inUsers: viewModel.activator(),
    };
    return App;

    var defaultPage = '';
    function activate(activationData) {

        defaultPage = 'ManageUsers';
        App.inUsers(convertSplatToModuleId(activationData.splat));

        router.activeItem.settings.areSameItem = function (currentItem, newItem, data) {
            if (currentItem != newItem) {
                return false;
            }
            else {
                App.inUsers(convertSplatToModuleId(data.splat));
                return true;
            }
        };
    }

    function showPage(name) {
        return function () {
            router.activate('#/Users/' + name);
            //router.navigateTo('#/Users/' + name);
            App.inUsers(convertNameToModuleId(name));
        };
    }

    function isPageActive(name) {
        var moduleName = convertNameToModuleId(name);
        return ko.computed(function () {
            return App.inUsers() === moduleName;
        });
    }

    // Internal methods
    function convertNameToModuleId(name) {
        return 'Main/Users/' + name + '/' + name;
    }

    function convertSplatToModuleId(splat) {
        if (splat && splat.length > 0) {
            return convertNameToModuleId(splat[0]);
        }
        return convertNameToModuleId(defaultPage);
    }
});

EDIT: (Main master page)

 function activate() {

        // my convention
        router.autoConvertRouteToModuleId = function (url) {
            return 'Main/' + url + '/index';
        };

        return router.activate('Home'); 
    }

Nav HTML for master:
<div class="btn-group">
                     <a href="#/home" class="btn btn-info">HOME</a>
                     <a href="#/resources" class="btn btn-info">RESOURCES</a>  
                     <a href="#/users" class="btn btn-info">USERS</a>               
 </div>    


Main master: 
  <div class="container-fixed"> 
   <div>
    <header>
        <!-- ko compose: {view: 'Main/masterNav'} -->
        <!-- /ko-->
    </header>
    <section id="content" class="main">
        <!--ko compose: {model: router.activeItem, 
            afterCompose: router.afterCompose,
            transition: 'entrance'} -->
        <!--/ko-->
    </section>        
    <footer>
        <!--ko compose: {view: 'Main/masterFooter'} --><!--/ko-->
    </footer>
  </div>
 </div>   
4

1 回答 1

2

您遇到的关于无法停用子路由视图的问题是因为viewmodel.activator()从该方法返回的可观察对象在 durandal 中强制执行激活器模式。那个 observable 需要一个 amd 模块而不是一个字符串。

即使字符串工作正常,因为compose绑定知道如何根据字符串加载模块.. viewmodel 激活器不知道如何从字符串加载模块。

因此,您需要将实际模块传递给 observable。

我之前创建的示例只使用了一个字符串,因此它将组成视图。但如果只有一个字符串,则激活器模式不起作用。因此,相反,您必须将require所有子路由 amd 模块放入调用代码中,然后不要使用该 convertSplatToModuleId方法。创建一个返回正确模块的新方法。

所以,像这样:

define(['durandal/system', 'durandal/viewModel', 'durandal/plugins/router'],
function (system, viewModel, router) {
    var App = {
        router: router,
        activate: activate,
        showPage: showPage,
        isPageActive: isPageActive,
        inUsers: viewModel.activator(),
    };
    return App;

    var defaultPage = '';
    function activate(activationData) {

        defaultPage = 'ManageUsers';
        convertSplatToModuleId(activationData.splat).then(function(activeModule){
            App.inUsers(activeModule);
        })


        router.activeItem.settings.areSameItem = function (currentItem, newItem, data) {
            if (currentItem != newItem) {
                return false;
            }
            else {
                convertSplatToModuleId(data.splat).then(function (module) {
                    App.inUsers(module);
                });
                return true;
            }
        };
    }

    function showPage(name) {
        return function () {
            router.activate('#/Users/' + name);
            //router.navigateTo('#/Users/' + name);
            convertNameToModuleId(name).then(function(module){
                App.inUsers(module);
            });            
        };
    }

    // Internal methods
    function convertNameToModuleId(name) {
        return system.acquire('Main/Users/' + name + '/' + name);
    }

    function convertSplatToModuleId(splat) {
        if (splat && splat.length > 0) {
            return convertNameToModuleId(splat[0]);
        }
        return convertNameToModuleId(defaultPage);
    }
});
于 2013-07-05T18:00:30.483 回答