Angular 调用具有角度依赖项的函数
使用Angular 5和UIRouter状态路由。根据此接口,我正在使用一个附加的自定义路由状态属性Angular 调用具有角度依赖项的函数,angular,typescript,configuration,routing,angular5,Angular,Typescript,Configuration,Routing,Angular5,使用Angular 5和UIRouter状态路由。根据此接口,我正在使用一个附加的自定义路由状态属性 interface AugmentedNg2RouteDefinition extends Ng2StateDeclaration { default?: string | ((...args: any[]) => string | Promise<string>); } 要使默认值真正起作用,我必须配置路由转换服务: @NgModule({ imports: [
interface AugmentedNg2RouteDefinition extends Ng2StateDeclaration {
default?: string | ((...args: any[]) => string | Promise<string>);
}
要使默认值真正起作用,我必须配置路由转换服务:
@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 { }
因此,当函数可能具有一些可注入的服务/值时,问题是调用默认值
配置函数的injector(config:(uiRouter:uiRouter,injector:injector,module:StatesModule)
)只能用于获取服务实例,但不能使用可注入参数调用函数
在AngularJS中,这将通过调用函数并注入其参数的$injector.invoke(…)
来实现
主要问题
当它被定义为带有可注入项的函数时,我应该如何处理default
。这是通过添加关于解析服务的部分来解决这个问题的一种方法
// 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
的结果,我使用该方法。这个方法为两个输入返回一个新的Promise
,这样我们就可以通过调用stateService来链接它,它将返回一个Promise
,这是TransitionHookFn的有效返回
要解析服务,您可以按如下方式更改接口:
interface AugmentedNg2RouteDefinition extends Ng2StateDeclaration {
default?: string | ((injector: Injector, ...args: any[]) => string | Promise<string>);
}
// 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';
});
AngularJS$injector.invoke在AngularJS中没有直接的对应项,因为可注入函数应该是在设计时定义的useFactory
提供程序
AngularJS中只有一个注入器实例,但AngularJS中有一个注入器层次结构,这也使事情变得复杂,因为调用函数的注入器上应该存在依赖关系
处理这个问题的惯用方法是定义所有预期作为提供程序调用的函数。这意味着一个函数被限制使用它在上定义的注入器的实例(根模块或子模块):
然后,工厂功能可以作为任何其他依赖项从喷油器中检索并调用:
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中构造函数定义的工作方式(Angular 5中不推荐使用)。区别在于类
接受使用数组或参数
静态属性进行注释的构造函数,注释应为数组数组,因为依赖项可能涉及修饰符(注入
,可选
,等等)
由于装饰器不适用于未注册为提供程序的函数,因此该数组应为普通数组,类似于AngularuseFactory
provider中的或deps
:
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();
}
}
可以绑定到喷油器实例:
const injectorInvoke = invoke.bind(injector);
injectorInvoke([Foo, Bar, (foo: Foo, bar: Bar) => {...}]);
调用函数的代码段修改为:
...
if (typeof defaultState === 'function' || Array.isArray(defaultState)) {
// possibly returns a promise
Promise.resolve(injectorInvoke(defaultState)).then(...)
} else { ... }
...
问题是default
可以在某个点上起作用,但事实上它不是。它到底是什么样子的?配置函数的注入器只能得到我在这里不能真正使用的注入器实例-这意味着什么?这些实例是什么?预期会出现哪些实例?这里需要清楚的问题陈述。@estus:默认值
可以是字符串,也可以是返回字符串或字符串承诺的函数。问题是此函数可能需要angular的DI容器提供的参数。这就是为什么要在AngularJS中使用$injector.invoke
,但是.invoke
函数在我的Angular 5代码上下文中不可用。您现在了解问题了吗?Angular中没有$injector.invoke,启用DI的函数应该定义为提供程序。这个函数和这些参数(服务?)是什么真的很重要。你的评论没有解释这一点,配置函数的注入器只能得到我在这里不能真正使用的注入器实例。请用详细解释您案例的示例更新问题,因为这个问题无法在一般情况下解决。@estus我知道没有$injector.invoke
。你觉得我为什么一开始就问这个问题?我显然没有正确地描述我的问题,因为您不了解default
state属性的作用。因此,注入参数(当default
是一个具有注入参数的函数时)可以是任何提供信息以决定应选择哪个默认子状态的内容。i、 一些认证服务。。。我的问题对于那些认真阅读的人来说已经足够详细了。这不是什么基本问题。这是一个进步的问题。@estus:我希望我经过严格编辑的问题现在更清楚、更容易理解。这也可能是因为我缺少一些知识,所以我不能把我的问题说得更清楚。似乎我遗漏了什么。您使用了一个简单的default
函数。无参数。。。但这并不是我想要解决的问题。至少不是我正在挣扎的例子。。。假设default
函数有一个服务参数:default:(myService:myService)=>{…}
。您现在将如何调用该函数?您必须以某种方式获得可注入服务实例。在AngularJS中,只需调用$injector.invoke()
,然后从DI容器中注入参数,但在Angular5中,我们没有invoke
函数……好的,我知道现在我读得不够仔细,所以我没有理解这是主要问题。然后,我会更改函数定义,将注入器
作为参数,然后解析函数中的服务
const injectorInvoke = invoke.bind(injector);
injectorInvoke([Foo, Bar, (foo: Foo, bar: Bar) => {...}]);
...
if (typeof defaultState === 'function' || Array.isArray(defaultState)) {
// possibly returns a promise
Promise.resolve(injectorInvoke(defaultState)).then(...)
} else { ... }
...