【问题标题】:Durandal: Conditional Start Module When Activating the RouterDurandal:激活路由器时的条件启动模块
【发布时间】:2013-11-13 06:06:20
【问题描述】:

我的 Durandal 应用程序在 shell.js 中的启动逻辑需要根据某些条件逻辑将用户发送到两个可能的视图之一。基本上,如果以前没有选择某些选项,我会将它们发送到设置页面,否则我会将它们发送到正常的起始页面。

以前,在 Durandal 1.x 中,我只会在调用激活时传递一个指示起始模块的字符串。但在 Durandal 2.x 中已被弃用。

首先,我想知道从路由数组的角度来看,推荐的方法是什么?我是否应该只注册两个路由,就好像启动模块都不是(如下所示),然后有条件地向数组添加另一个路由,默认路由为 ''?

{ route: "setup", moduleId: "setup", title: "Setup", nav: false },
{ route: "Students", moduleId: "students", title: "Students", nav: false }

我的问题的第二部分涉及如何处理调用 Web 服务的需求,这是我确定哪个模块是启动模块的条件逻辑的一部分。我的启动逻辑涉及检查浏览器的本地存储,但有时我还需要向服务器发出 ajax 请求以获取一些信息。

我的理解是 router.activate() 是一个承诺。我真的可以创建自己的承诺并在 ajax 调用完成后通过调用 router.activate() 来解决它吗?还是我需要另一种方法来处理它?我认为我可能会如何处理的示例代码:

var deferred = $.Deferred();

//Setup and conditional logic here
var routes = setupRoutes();

$.get('/api/myStartupEndpoint')
 .done(function(results) {
    //check results and maybe alter routes
    deferred.resolve(router.map(routes).activate());
 });

return deferred.promise();

这有意义吗?我仍在将我的应用程序转换为 Durandal 2.0.1,所以我还不能尝试这个,但不管它是否可以,我都想知道在这种情况下推荐的方法是什么。

【问题讨论】:

    标签: durandal durandal-2.0


    【解决方案1】:

    我会这样做 - 实际上我认为这与您已经在思考的方式相似,所以我希望它是有道理的:

    1. 在您的 main.js 中,无论在什么情况下,都将您的应用程序根目录设置为相同的模块。由于 D2 的主要功能之一是子路由器,我建议使用模块名称“root”作为您的应用程序根目录,因为它更容易与“shell”模块(我用于设置子路由器)区分开来:

      app.start().then(function () {
          app.setRoot("root", "entrance");
      });
      
    2. 在您的根模块中,按照您的描述设置路由:

      { route: "setup", moduleId: "setup", title: "Setup", nav: false },
      { route: "students", moduleId: "students", title: "Students", nav: false }
      
    3. 当您的根模块激活时,检查用户是否已设置。使用该检查的结果来确定您是否希望将用户发送到设置页面或学生页面。但请注意,您必须在重定向之前激活您的路由器;您可以在这里使用$.when 为您提供帮助:

      var checkUserSetup = function () {
          var deferred = $.Deferred();
      
          // check local storage, fire off ajax request, etc.
          // resolve the deferred once you know if the user is setup or not
          deferred.resolve(false);
      
          return deferred.promise();
      };
      
      root.activate = function() {
          mapRoutes();
      
          var deferred = $.Deferred();
      
          $.when(checkUserSetup(), router.activate()).done(function(isUserSetup) {
              if (isUserSetup) {
                  router.navigate("students");
      
              } else {
                  router.navigate("setup");
              }
      
              deferred.resolve();
          });
      
          return deferred.promise();
      }
      

    希望这也能回答您问题的第二部分;但以防万一 - 是的,您可以从 activate 方法返回一个承诺,并且 durandal 将“阻止”,直到您解决了该承诺。但是,请注意路由器的activate 方法也返回一个promise - 所以你的代码不会完全 工作。你正在用另一个 deferred 解决你的 deferred;你需要做更多这样的事情:

    root.activate = function() {
        var deferred = $.Deferred();
    
        //Setup and conditional logic here
        var routes = setupRoutes();
    
        $.get('/api/myStartupEndpoint')
            .done(function(results) {
                //check results and maybe alter routes
                //don't resolve the deferred until the router has completed activation
                router.map(routes).activate().done(deferred.resolve);
            });
    
        return deferred.promise();
    }
    

    希望对您有所帮助。

    【讨论】:

    • 感谢您的解释!我最终使用了您展示的第二种技术(基本上与我最初尝试做的事情相同,除了在路由器激活承诺完成后解决承诺)。我还没有研究子路由器功能,也没有真正看到我需要或想要在我的应用程序中执行此操作的位置。所以我决定暂时搁置“根”模块技术,至少在我更好地理解用例之前。谢谢!
    • @gerrod 我正在尝试做一些与此非常相似的事情,但我认为我在您发布的示例中遗漏了一些东西。在router.navigate("students") 之前调用router.activate() 时出现“找不到路由”,因为没有'' 路由。还是应该有,但这里不包括?如果是这样,它应该指向什么?!如果你有时间,很高兴加入聊天。谢谢
    • 嗨@Shai - 我需要查看示例,但您通常希望包含默认路由(''),或者您可以使用mapUnknownRoutes 尝试找出哪个路线未正确映射(请参阅此处的“处理未知路线” - durandaljs.com/documentation/Using-The-Router.html)。希望有帮助!
    • 谢谢。是的,我通过添加一个默认路由 ('') 让它工作,它指向一个只有 canActivate: function() { return false; } 的视图模型。这让我可以有条件地运行router.navigate() 以正确选择起始页。为您的帮助干杯...我对“将您的路线设置为 [...] 设置 [...] 学生”感到困惑,并且没有意识到需要默认值!
    猜你喜欢
    • 2014-08-30
    • 2015-12-19
    • 1970-01-01
    • 2014-07-01
    • 2018-12-26
    • 1970-01-01
    • 2016-05-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多