Angular 2 中的动态路由加载失败。 (测试版)

Dynamic Route Loading in Angular 2 Fails. (Beta)

我想从以 JSON、

格式获取的服务动态加载 @RouteConfig 的路由
[
  { "path" : "/about" , "name" : "About" , "component" : "AboutComponent" },
  { "path" : "/contact" , "name" : "Contact" , "component" : "ContactComponent" }
]

以下是将其推入 RouteDefinition 数组的代码,

for (let i = 0; i < data.length; i++) {
  //console.log(data[i].path+" "+data[i].name+" "+data[i].component);
  this.routeConfigArray.push({ //routeConfigArray : RouteDefinition
    'path': data[i].path,
    'name': data[i].name,
    'component': data[i].component
  });
  this._router.config(this.routeConfigArray);   // THIS FAILS TO CONFIG PATHS ON ROUTER
}

'component':data[i].component 需要类名,因为它通过字符串 class 接收类名。如何将包含 classname 的字符串转换为 class??

我也试过路线 class 使用 :

this.routeConfigArray.push(new Route({path: data[i].path, name: data[i].name, component:data[i].component}));

控制台错误:

Component for route "/about" is not defined, or is not a class. i have tried numerous ways like using eval("new "+data[i].component+"()); || new window[data[i].component] .

我被困在这个问题上,对于如何解决这个问题真的很困惑。

TypeScript 以某种方式将导入编译为 javascript,您可以尝试类似这样的方法来使用 eval()(畏缩)。如果 typescript 的编译方式不同,这显然是行不通的,但是检查它是否能以任何方式工作很有趣 :)

for (let i = 0; i < data.length; i++) {
  this.routeConfigArray.push({ //routeConfigArray : RouteDefinition
    path: data[i].path,
    name: data[i].name,
    component: getComponent(data[i].component)
  });
  this._router.config(this.routeConfigArray);   
}

function getComponent(comp : string) : Function {
    //convert camelCase to underscore notation
    let component : string = comp;
    component = component[0].toLowerCase() + component.slice(1);
    component = component.replace(/([A-Z])/g, function(match) {
        return '_' + match.toLowerCase();
    });
    component += '_1';
    return eval(component[comp])
}

附录

作为您自己使用 AsyncRoute 的解决方案的补充,我相信您实际上已经有了一个很好的解决方案。也许如果您以某种方式放置所有页面,则可以从 path 中提取 resource 位置,但这不是必需的。 (我的意思是从 path 字符串 /aboutresource 字符串 ./app/about/about.component 使用小算法应该不难。但这可能需要更新。

无论如何,您可以使用 AsyncRoute

尝试类似的操作

警告:前方代码未经测试

let routes : any[] = [
    { "path" : "/about" , "name" : "About" , "component" : "AboutComponent", "route": "/About" , "resource" : "./app/about/about.component" },
    { "path" : "/contact" , "name" : "Contact" , "component" : "ContactComponent", "route": "/Contact" , "resource" : "./app/contact/contact.component" }
];

routes.forEach((route : any) => {
    this.routeConfigArray.push(
        new AsyncRoute({
            path : route.path,
            loader : () => System.import(route.resource).then(m => m[route.component]),
            name : route.name
        })
    );
});

this._router.config(this.routeConfigArray);

你太棒了@PierreDuc,我只是在看正则表达式来构建相同的功能,我想指出一些编辑以使其处于工作状态....

for (let i = 0; i < data.length; i++) {
  this.routeConfigArray.push({ //routeConfigArray : RouteDefinition
    'path': data[i].path,
    'name': data[i].name,
    'component': getComponent(data[i].component).constructor
  });
  this._router.config(this.routeConfigArray);   
}

function getComponent(comp : string) : Function {
    //convert camelCase to underscore notation
    let component : string = comp;
    component = component[0].toLowerCase() + component.slice(1);
    component = component.replace(/([A-Z])/g, function(match) {
        return '_' + match.toLowerCase();
    });
    component += '_1.';
    return eval("new "+component+comp+"()")
}

再次感谢您,伙计,现在处于 运行 模式!!!呸!

您可以使用另一种方法,来自@Pierre 和@Pratik 的方法基于 returns 类 的名称:

Object.prototype.getName = function() { 
  var funcNameRegex = /function (.{1,})\(/;
  var results = (funcNameRegex).exec((this).constructor.toString());
  return (results && results.length > 1) ? results[1] : "";
};

在您的组件中,您可以像这样动态配置您的路由:

ngOnInit() {
  this.routes = [
    {
      path: '/test', component: 'OtherComponent', name: 'Test'
    }
  ];
  this.configureRoutes(this.routes);
  this.router.config( this.routes);
}

configureRoutes(routes) {
  var potentialComponents = [ OtherComponent ];
  routes.forEach((route) => {
    route.component = potentialComponents.find((component) => {
      return component.name === route.component;
    });
  });
}

这需要预先了解路由中可能涉及的潜在组件。

请参阅此 plunkr 进行演示:https://plnkr.co/edit/KKVagp?p=preview

看到这个问题:

  • How do I get the name of an object's type in JavaScript?

更新上述第一个场景: 上面的动态加载 UI 上的路由,但要做到这一点,我必须在我的 AppComponent

中提及它
import {AboutComponent} from '/path';
import {ContactComponent} from '/path';

//and then either include it in a directive or mention The component Name some place in the code

但这违背了目的'Dynamic Loading',因为我必须知道哪些组件会被请求并且不能延迟加载它们。假设我为 500 个组件执行此操作,我必须加载这 500 个组件,然后仅从上面提到的 JSON 中选择必须加载到 UI.

上的组件

解决方案(已完成并测试)==> 我现在不必在任何指令中提及我想在 任何导入语句 中加载的组件。 从而使其延迟加载和完全动态化

如何 通过使用 AsyncRoute Class.

这是我的新 JSON
//"route"是映射到[routerLink]="['/Home']" & "resource"是component的实际路径

 [
  { "path" : "/about" , "name" : "About" , "component" : "AboutComponent", "route": "/About" , "resource" : "./app/about/about.component" },
  { "path" : "/contact" , "name" : "Contact" , "component" : "ContactComponent", "route": "/About" , "resource" : "./app/about/about.component" },
  { "path" : "/blog" , "name" : "Blog" , "component" : "AboutComponent", "route": "/About" , "resource" : "./app/about/about.component" },
  { "path" : "/news" , "name" : "News" , "component" : "AboutComponent", "route": "/About" , "resource" : "./app/about/about.component" }
]

现在来看代码,我在这里获取这个 JSON 并将其添加到 routeConfigArray : RouteDefinition[] 并调用路由器的 .config(routeConfigArray)

  let routes : any[] = data; // consist the json data in array


routes.forEach((route : any) => {
        this.routeConfigArray.push(
            new AsyncRoute({
                path : route.path,
                loader : () => System.import(route.resource).then(m => m[route.component]),
                name : route.name
            })
        );
    });

    this._router.config(this.routeConfigArray);

这就是它的工作原理!!!