【问题标题】:Aurelia load routes dynamically / from fetchAurelia 动态/从 fetch 加载路由
【发布时间】:2017-02-17 21:51:24
【问题描述】:

我想动态加载菜单选项。所以我想知道最好的方法

我可以在页面加载后使用下面的代码添加路由。这适用于正常导航,但在刷新期间不起作用。

可以配置路由器返回一个承诺/我如何将菜单项加载到路由中?

 @inject(HttpClient)
 export class DocumentMenu {
  router: Router;
  documents : IDocument[];
  heading = 'Document Router';

  constructor(public http: HttpClient) {}

 activate(): void {

    this.http.fetch('http://localhost:17853/Document/GetDocuments?folderID=13244')
      .then<IDocument[]>(response => response.json())
      .then<IDocument[]>(docs => {    
      if ( docs ){
        for( var doc of docs){
          this.router.addRoute( { route : doc.DocumentID.toString(), name : doc.Name, moduleId: './documents/document', nav:true, title: doc.Name });
        }
        this.router.refreshNavigation();
      }
      return docs;
    });

 }

configureRouter(config: RouterConfiguration, router: Router) {

  var routes = new Array();
  routes.push( 
  { route: 'index', name: 'index-name', moduleId: './documents/index', nav: false, title: 'Documents' } );
  routes.push(       { route: '', redirect: 'index' } );

  config.map( routes );
  this.router = router;
}
}

【问题讨论】:

  • 可以静态添加所有路由,而不是动态添加路由,然后使用授权管道检查用户是否可以访问它
  • @FabioLuz 可以工作,除非我不知道路线是什么。它有点像一个浅树结构,用户可以在其中选择一个包含 0 到 15 个文档的文件夹。我希望文档成为导航选项
  • 有没有试过在构造函数中做?
  • @Matt-McCabe 刚刚做了,效果很好,将发布答案

标签: aurelia


【解决方案1】:

这并不能回答您的问题,但我认为它可能对您和其他有类似问题的人有所帮助。

动态路由反模式

您的应用程序有许多不同的路由,所有这些路由都因应用程序的状态而异。因此,你必须先获取数据,然后构建路由,然后将它们注册到路由器。

这是一种反模式的原因是,当 Aurelia 本身是用描述动态内容的静态方式构建时,您将需要不断地根据应用程序的状态更新路由器。

动态路由同类数据

假设您正在构建 Google 云端硬盘,并且您有许多不同的文件,这些文件可能会随着用户添加和删除它们而改变。对于这种情况,您有两类路由:文件夹和文档。因此,您为每条路线制定一条路线。

configureRouter(config) {
    config.map([
        { route: 'folder/:id', moduleId: 'folder' }
        { route: 'document/:id', moduleId: 'document' }
    }
}

class FolderViewModel {
    activate({ id }) {

        // get your specific folder data and load it into your folder view model
        this.fetch('getDocuments?folderId=${id}')
    }   
}

class DocumentViewModel {
    activate({ id }) {

        // get your specific document and load it into your document view model
        this.fetch('getDocuments?documentId=${id}')
    }
}

动态路由异构数据

假设您想构建 YouTube。当user mjd10d 登录时,欢迎他观看视频,尽情享受,但他不是高级内容创建者,也无权访问网站的内容创建部分。处理此问题的最佳方法是将所有可能的路由保留在您的应用程序中,并根据 AuthorizeStep 中的用户凭据过滤它们。

configureRouter(config, router) {
  config.addPipelineStep('authorize', AuthorizeStep);
}

@inject(UserSession)
class AuthorizeStep {

  constructor(UserSession) {
    this.user = UserSession;
  }

  run(navigationInstruction, next) {
    var instructions = navigationInstruction.getAllInstructions()
    if (!this.authorized(instructions.config)) {
      return Redirect('404');
    }
    return next();
  }

  authorized(routeConfig) {

    // something smart that returns false if unauthorized
    return this.user.permissionLevel > routeConfig.requiredPermission;
  }
}

虽然并非所有情况都与授权相关,但您始终可以使用 addPipelineStep API 注册自己的管道步骤

【讨论】:

  • 好吧,这个解决方案赢了,但这只是因为范围扩大。 (如上所述,它并没有真正回答问题)
【解决方案2】:

您可以通过在“configureRouter”方法(在 app.ts 中)中使用单个固定(静态)路由来动态添加路由(在启动时或任何时候),然后动态添加所有其他路由,当您的 fetch 完成时,如下所示:

configureRouter(config, router) {
    config.title = 'SM';

    //configure one static route:
    config.map([
        { route: ['', 'welcome'], name: 'welcome', moduleId: 'welcome/welcome', title: 'Welcome' } 
    ]);

    routeMaps(this.navRepo) //your repo/service doing the async HTTP fetch, returning a Promise<Array<any>> (i.e., the routes)
        .then(r => {
            r.forEach(route => this.router.addRoute(route));
            //once all dynamic routes are added, refresh navigation:
            this.router.refreshNavigation();
        });

    this.router = router;
}

“routeMaps”函数只是 repo 调用的包装器,并将结果映射到路由项数组。

【讨论】:

    【解决方案3】:

    您可以在激活时返回一个承诺。如果 activate() 返回一个 promise,configureRouter() 不会触发,直到 activate() 中返回的 promise 被解决。

    我最终准备了如下激活的路线:

    activate(){
        return this.http.fetch('url')
           .then(response => response.json())
           .then(docs => {    
               this.routerMapped = docs;
           });       
    }
    
    configureRouter(config, router) {
        //build the routes from this.routermapped if necessary
        config.map( this.routerMapped );
        this.router = router;  
    }
    

    【讨论】:

    • configureRouter() 总是在 activate() 之前触发 :-(
    • 这对我来说似乎很奇怪。刚刚对其进行了测试,并且 activate() 在 configureRouter() 之前触发。看看这个gist。 configureRouter 按预期在激活后 5 秒触发。
    • 我认为这是 AppRouter 和“常规”路由器之间的区别。您的要点适用于应用路由器,而我的评论是在测试子路由器之后。感谢您揭露差异。 Aurelia 文档说:“Aurelia 有两个路由器类,AppRouter 和 Router。AppRouter 扩展了 Router 类并且是主要的应用程序路由器。路由器用于任何子路由器,包括嵌套的子路由器。”
    【解决方案4】:

    为了完成这项工作,我在构造函数中使用同步请求创建了路由

    export class DocumentMenu {
    ...
    routes  : RouteConfig[];
    
    constructor(http: HttpClient) {
      this.http = http;
    
      var folderID = window.location.hash.split('/')[2]
    
      this.routes = new Array<RouteConfig>();
      this.routes.push ( { route: 'index', name: 'index-name', moduleId: './documents/index', nav: false, title: 'Documents' });
      this.routes.push ( { route: '', redirect: 'index' } );
    
      for( var route of this.getRoutes( folderID )){
        this.routes.push( route );
      }
    }
    
    getRoutes(folderID: string) :  RouteConfig[]
    {
      var routes = new Array<RouteConfig>();
      var docsURL = 'http://localhost:17853/Document/GetDocuments?folderID=' + folderID;
    
      // synchronous request   
      var docsResp = $.ajax({
          type: "GET",
          url: docsURL,
          async: false,
          cache:false
      }).responseText;
    
      var docs = JSON.parse( docsResp );
    
      for( var doc of docs ){
        routes.push( { route : doc.DocumentID.toString(), name : doc.Name, moduleId: './documents/document', nav:true, title: doc.Name });
      }
    
      return routes;
    }
    
    configureRouter(config: RouterConfiguration, router: Router) {  
       config.map( this.routes );
       this.router = router;
     }
    ...
    

    【讨论】:

    • 有道理,听起来您可能想包装一个方法来刷新路由(添加文档时?)或者只是刷新页面。
    • 请查看我的回答,了解可能对您更有效的策略
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-09-22
    • 2021-01-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-22
    相关资源
    最近更新 更多