如何使用durandal路由器激活对话框?

时间:2014-10-02 09:25:09

标签: durandal durandal-2.0 durandal-navigation

我很乐意使用 #signin 路线,该路线会在之前的任何页面上打开一个对话框。

让我们通过以下路线考虑这个示例应用程序:

router.map([
    {route: '', moduleId: 'vm/home', title: "Home"},
    {route: 'about', moduleId: 'vm/about', title: "About"},
    {route: 'signin', moduleId: 'vm/signin', title: 'Sign In'}
]);

以下是示例用例:

  1. 用户在#上并导航至#signin:我们应该在主页页面<主页页面<上方看到登录对话框/ p>

  2. 用户在#about上并导航至#signin:我们应该会在关于页面<关于页面<上方看到登录对话框/ p>

  3. 用户导航至http://localhost:9000/#signin:我们应该在主页

  4. 之上看到登录对话框
  5. 用户在#signin并关闭对话框:我们应该看到对话框后面的页面(后面总是有一页)。

3 个答案:

答案 0 :(得分:2)

对话框和路由器都是插件,彼此之间没有交互。

同样具有路由器显示对话框将忽略路由器的工作方式 - 它有一个div,它将内容转储到。对话存在于所有这些之外。

但是如果你想(我也可以这样做),你可以试试这个。

dialog: true添加到路线图中。

覆盖router.loadUrl方法。检查路线是否是我们之前标记的对话路线,然后改为激活对话框。

我会将对话框设置为子路径,这样您就可以知道在对话框下面显示哪个视图。否则你可能只需要显示任何对话框并完全忽略路由。

编辑:我不认为这实际上会完全奏效。 loadUrl返回一个布尔值。您可以打开对话框并返回false以取消导航。

Edit2:

我的尝试

loadUrl方法遍历所有路由,并且每个路由都有一个回调,所以理想情况下我们需要将逻辑插入到这个数组中。

for (var i = 0; i < handlers.length; i++) {
    var current = handlers[i];
    if (current.routePattern.test(coreFragment)) {
        current.callback(coreFragment, queryString);
        return true;
    }
}

使用路由器route方法添加此数组。 Durandal在映射路由时调用此方法,因此理想情况下我们可以在路由配置中添加一些额外的参数,让Durandal处理这些。但是configureRoute函数是路由模块的内部函数,因此我们需要对其进行编辑,并确保在将来更新Durandal时复制更改。

我创建了一个新的对话路由列表:

{ route: 'taxcode/add(/:params)', moduleId: 'admin/taxcode/add', title: 'Add Tax Code', hash: '#taxcode/add', nav: false, dialog: true, owner: '#taxcodes' },
{ route: 'taxcode/edit/:id', moduleId: 'admin/taxcode/edit', title: 'Edit Tax Code', hash: '#taxcode/edit', nav: false, dialog: true, owner: '#taxcodes' }

拥有者的想法是,如果有一个初始路线是这样的情况,我们需要在对话框后面的东西。

现在替换了router.route中的configureRoute来电:

router.route(config.routePattern, function (fragment, queryString) {
    if (config.dialog) {
        if (!router.activeInstruction()) {
            // No current instruction, so load one to sit in the background (and go back to)
            var loadBackDrop = function (hash) {
                var backDropConfig = ko.utils.arrayFirst(router.routes, function (r) {
                    return r.hash == hash;
                });
                if (!backDropConfig) {
                    return false;
                }
                history.navigate(backDropConfig.hash, { trigger: false, replace: true });
                history.navigate(fragment, { trigger: false, replace: false });
                queueInstruction({
                    fragment: backDropConfig.hash,
                    queryString: "",
                    config: backDropConfig,
                    params: [],
                    queryParams: {}
                });
                return true;
            };

            if (typeof config.owner == 'string') {
                if (!loadBackDrop(config.owner)) {
                    delete config.owner;
                }
            }
            if (typeof config.owner != 'string') {
                 if (!loadBackDrop("")) {
                      router.navigate("");
                      return; // failed
                 }
            }
        }
        var navigatingAway = false;
        var subscription = router.activeInstruction.subscribe(function (newValue) {
            subscription.dispose();
            navigatingAway = true;
            system.acquire(config.moduleId).then(function (dialogInstance) {
                dialog.close(dialogInstance);
            });
        })
        // Have a route. Go back to it after dialog
        var paramInfo = createParams(config.routePattern, fragment, queryString);
        paramInfo.params.unshift(config.moduleId);
        dialog.show.apply(dialog, paramInfo.params)
            .always(function () {
                if (!navigatingAway) {
                    router.navigateBack();
                }
            });
    } else {
        var paramInfo = createParams(config.routePattern, fragment, queryString);
        queueInstruction({
            fragment: fragment,
            queryString: queryString,
            config: config,
            params: paramInfo.params,
            queryParams: paramInfo.queryParams
        });
    }
});

确保将dialog导入模块。

答案 1 :(得分:1)

当使用带有家庭视图模型的激活数据的技巧时,也许不需要所有这些。 看看我创建的Github repo作为答案。

这个想法是路由接受一个可选的激活数据,你的家庭虚拟机的激活方法可以检查并相应地显示所需的模态。

这样做的好处是您根本不需要触摸现有的Durandal插件或核心代码。 我不确定这是否完全符合您的要求,因为要求没有详细说明。

更新: 好的,我现在已经更新了repo以满足泛化的额外要求。基本上现在我们在shell中利用Durandal的Pub / Sub机制,或者将它放在你想要的任何地方。在那里我们听取路由器nav-complete事件。发生这种情况时,请检查指令集并搜索给定的关键字。如果是这样,那么就开始模态。通过使用导航完成事件,我们还确保主VM正确且完全加载。 对于那些想要导航到#signin的黑客,只需手动将它们重新路由到任何你想要的地方。

答案 2 :(得分:0)

在评论中扩展我的建议,也许这样的事情会起作用。只需在router:route:activating或其他类似事件之一上配置事件挂钩,并拦截/#signin的激活。然后使用此挂钩作为显示对话框的方法。请注意,此示例仅用于说明目的。在我工作的时候,我无法提供一个有效的例子。 :/我回家后可以完成它,但至少这会给你一个想法。

router.on('router:route:activating').then(function (instance, instruction) {
  // TODO: Inspect the instruction for the sign in route, then show the sign in 
  // dialog and cancel route navigation.
});