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

时间:2016-03-09 09:01:10

标签: angularjs routing typescript angular angular2-routing

我想从一个以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需要Classname,它通过String类接收它。如何将包含classname的字符串转换为类?

我也尝试使用Route类:

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

控制台错误:

  

路由“/ about”的组件未定义,或者不是类。   我尝试了很多方法,比如使用eval("new "+data[i].component+"()); || new window[data[i].component] .

我对此感到困惑,并对如何解决这个问题感到困惑。

4 个答案:

答案 0 :(得分:1)

TypeScript以某种方式编译导入到javascript中,你可以尝试这样的东西来使用eval()(畏缩)。如果打字稿编译方式不同,这显然是行不通的,但检查一下这是否有效是很有趣的:)

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的自己的解决方案的补充,我相信你实际上已经有了很好的解决方案。也许如果您以某种方式放置所有页面,则可以从resource中提取path位置,但这不是必需的。 (我的意思是从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);

答案 1 :(得分:1)

你太好了@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+"()")
}

再次谢谢你老兄,它现在处于运行模式!唷!

答案 2 :(得分:1)

您可以使用@Pierre和@Pratik中的另一种方法,该方法基于返回类名称的方法:

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 for demo:https://plnkr.co/edit/KKVagp?p=preview

看到这个问题:

答案 3 :(得分:0)

更新到上面的第一个场景: 以上动态加载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

但这违背了“动态加载”的目的,因为我必须知道要求哪些组件,也不能延迟加载它们。假设我为500个组件执行此操作,我必须加载这500个组件,然后只需从上面提到的JSON中选择必须在UI上加载的组件。

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

如何 使用 AsyncRoute 类。

这是我的新JSON
//“route”是将它映射到[routerLink] =“['/ Home']”&amp; “resource”是组件的实际路径

 [
  { "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);

这就是它的运作方式!