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
字符串 /about
到 resource
字符串 ./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);
这就是它的工作原理!!!
我想从以 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
字符串 /about
到 resource
字符串 ./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);
这就是它的工作原理!!!