使用Angular 5和UIRouter状态路由。我根据此界面使用了其他自定义路由状态属性。
interface AugmentedNg2RouteDefinition extends Ng2StateDeclaration {
default?: string | ((...args: any[]) => string | Promise<string>);
}
当我定义一个抽象状态时,我现在也可以为它添加一个default
属性,所以当一个人试图路由到一个抽象状态时,默认应该将它们重定向到配置的 default < / em>儿童状态。
从上面的界面可以理解,default
可以定义为以下任何一种:
// relative state name
default: '.child',
// absolute state name
default: 'parent.child',
// function with DI injectables
default: (auth: AuthService, stateService: StateService) => {
if (auth.isAuthenticated) {
return '.child';
} else {
return stateService.target('.login', { ... });
}
}
// function with DI injectables returning a promise
default: (items: ItemsService) => {
return items
.getTotal()
.then((count) => {
return count > 7
? '.simple'
: '.paged';
});
}
要实际使default
正常工作,我必须配置路由转换服务:
@NgModule({
imports: [
...
UIRouterModule.forChild({ // or "forRoot"
states: ...
// THIS SHOULD PROCESS "default" PROPERTY ON ABSTRACT STATES
config: (uiRouter: UIRouter, injector: Injector, module: StatesModule) => {
uiRouter.transitionService.onBefore(
// ONLY RUN THIS ON ABSTRACTS WITH "default" SET
{
to: state => state.abstract === true && !!state.self.default
},
// PROCESS "default" VALUE
transition => {
let to: transition.to();
if (angular.isFunction(to.default)) {
// OK WE HAVE TO EXECUTE THE FUNCTION WITH INJECTABLES SOMEHOW
} else {
// this one's simple as "default" is a string
if (to.default[0] === '.') {
to.default = to.name + to.default;
}
return transition.router.stateService.target(to.default);
}
}
);
}
})
]
})
export class SomeFeatureModule { }
所以问题是当default
是一个可能有一些可注射服务/值的函数时调用config: (uiRouter: UIRouter, injector: Injector, module: StatesModule)
......
配置函数的注入器($injector.invoke(...)
)只能用于获取服务实例,但不能使用可注入参数调用函数。
在AngularJS中,这将由default
完成,它将调用该函数并注入其参数。
如果将$("table tr:not('.jack')").filter(":odd").children().css("background-color", "red");
定义为具有注射剂的功能,我该如何处理。
答案 0 :(得分:1)
Angular中与AngularJS $injector.invoke
没有直接对应关系,因为可注入函数应该是在设计时定义的useFactory
提供者。
AngularJS中只有一个注入器实例,但Angular中有一个注入器层次结构,这也使事情变得复杂,因为调用一个函数的注入器应该存在依赖关系。
处理此问题的惯用方法是定义预期作为提供程序调用的所有函数。这意味着函数仅限于使用其定义的注入器实例(根模块或子模块):
export function fooDefaultStateFactory(baz) {
return () => baz.getStateName();
}
@NgModule({
providers: [
Baz,
{
provider: fooDefaultStateFactory,
useFactory: fooDefaultStateFactory,
deps: [Baz]
}
],
...
})
...
// relative state name
default: '.child',
...
// function with DI injectables
default: fooDefaultStateFactory
然后可以从注入器中检索工厂函数作为任何其他依赖项并调用:
transition => {
...
if (typeof to.default === 'string') {
...
} else if (to.default) {
const defaultState = injector.get(to.default);
if (typeof defaultState === 'function') {
// possibly returns a promise
Promise.resolve(defaultState()).then(...)
} else { ... }
}
}
与任何函数一起使用的$injector.invoke
的副本应该与Angular 2/4 Class
helper中构造函数定义的工作原理大致相似(在Angular 5中已弃用)。区别在于Class
接受使用数组或parameters
静态属性注释的构造函数,注释应该是一个数组数组,因为依赖项可能涉及装饰器(Inject
,{ {1}}等)。
由于装饰器不适用于未注册为提供者的函数,因此该数组应该是纯文本的,类似于Angular中的AngularJS implicit annotations或Optional
{{1}提供者:
deps
可绑定到进样器实例:
useFactory
调用函数的代码段被修改为:
function invoke(injector, fnOrArr) {
if (Array.isArray(fnOrArr)) {
const annotations = [...fnOrArr];
const fn = annotations.pop();
const deps = annotations.map(annotation => injector.get(annotation));
return fn(...deps);
} else {
return fnOrArr();
}
}
答案 1 :(得分:0)
这是您可以通过添加有关解析服务的部分来解决此问题的一种方法。
// THE IMPORTANT PART
config: (uiRouter: UIRouter, injector: Injector, module: StatesModule) => {
uiRouter.transitionService.onBefore(
// HookMatchCriteria
{
to: state => state.abstract === true && !!state.self.default
},
// TransitionHookFn
transition => {
let to: transition.to();
if (typeof to.default === "string") {
return transition.router.stateService.target(to.default);
} else if (typeof to.default === "function") {
let functionPromise = Promise.resolve(to.default(injector));
return functionPromise.then((toDefault) => transition.router.stateService.target(toDefault));
}
}
检查默认值是否为string
的第一部分是显而易见的。
在第二个if
中,我检查参数是否为函数,这会自动将其视为TypeScript中的函数,因此可以直接调用它。在结果上可以是Promise<string>
或string
i,然后使用Promise.resolve(value)方法。此方法为两个输入返回一个新的Promise<string>
,然后我们可以通过调用stateService来链接它,它将返回Promise<TargetState>
,这是TransitionHookFn的有效返回。
要解析服务,您可以更改界面,如下所示:
interface AugmentedNg2RouteDefinition extends Ng2StateDeclaration {
default?: string | ((injector: Injector, ...args: any[]) => string | Promise<string>);
}
然后你也会在调用函数时始终发送注入器,因为你在config方法中有它。如果预期所有参数都是服务,则删除...args
并发送注入器。
然后,您作为样本提供的函数将如下所示:
// relative state name
default: '.child',
// absolute state name
default: 'parent.child',
// function with DI injectables
default: (injector: Injector) => {
let auth: AuthService = injector.get(AuthService);
let stateService: StateService = injector.get(StateService);
if (auth.isAuthenticated) {
return '.child';
} else {
return stateService.target('.login', { ... });
}
}
// function with DI injectables returning a promise
default: (injector: Injector) => {
let items: ItemsService = injector.get(ItemsService);
return items
.getTotal()
.then((count) => {
return count > 7
? '.simple'
: '.paged';
});