2014-10-02 79 views
1

我很喜欢#signin路线,它会在任何页面之前打开一个对话框。如何使用durandal路由器来激活对话框?

让我们看看这个示例应用程序下面这样的路线:

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:我们应该看到登录对话顶部首页页面

  2. 用户在#about并导航到#signin:我们应该看到登录上的关于

  3. 用户顶部对话框导航到http://localhost:9000/#signin:我们应该看到登录对话框上的主页顶部页面

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

+0

[如何用DurandalJS创建“完整页面对话框”的可能的重复](http://stackoverflow.com/questions/18537647/how-to-create-full-page-dialog-with-durandaljs) – 2014-10-03 09:51:28

+0

@Tambo ,它不是重复的,op正在寻找没有路由的对话框,因为我正在寻找一个解决方案,其中对话框就像是拥有自己路由的“页面”。 – Dziamid 2014-10-03 13:18:57

回答

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' } 

所有者的想法是,如果在最初的路线是这样的一个情况下,我们需要对话背后的东西。

现在取代了configureRoute与此router.route电话:

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到模块。

+0

我很想看到一个例子!我不清楚'loadUrl'中要重写什么,因为它基本上只是匹配具有模式的路由。 – Dziamid 2014-10-08 11:59:25

+0

我会在某个时刻出发。我刚开始使用儿童路由器,因此对我来说也是非常新颖的! – Tim 2014-10-08 15:33:34

+0

另一种可能性是您可以挂接到许多路由器事件中的一个,例如'router:route:activating',并在那里处理对话。 – Brett 2014-10-08 16:16:24

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. 
}); 
+0

这似乎是一个优雅的解决方案。慢慢来一个例子。 – Dziamid 2014-10-09 19:02:35

1

那么也许所有这一切都不需要使用您的家庭viewmodel的激活数据的技巧。 看看我创建的答案为Github repo

这个想法是,路线接受一个可选的激活数据,您的家庭虚拟机的激活方法可能会检查并相应地显示所需的模式。

这种方式的好处是,您根本不需要触摸现有的Durandal插件或核心代码。 虽然我不确定这是否完全符合您的要求,因为要求没有详细说明任何内容。

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

+0

回购+1,但有一点你错过了。我真的希望这个对话框'在任何页面之前打开'。您的解决方案将需要修复您可以登录的所有潜在视图模型。你能想出一个更广泛的解决方案吗? – Dziamid 2014-10-11 08:43:21

+0

我已更新到问题以更好地说明可能的用例,请看看! – Dziamid 2014-10-11 09:12:13

+0

好吧,我已经更新了我的帖子以及github回购 – zewa666 2014-10-11 11:56:49

相关问题