Angular 7:为 ngComponentOutlet 注入依赖项
Angular 7: injection with dependencies for ngComponentOutlet
我需要为我的 ngComponentOutlet
使用某种 @Input()
装饰器。
但是Angular好像没有这个功能。相反,我想在出口组件中传递的所有内容都应通过 Injector
.
提供
如果我想启动我想提供给内部注射器的东西,那很好 class。但我需要更深入地研究并在创建 Injector 步骤时提供某种可观察变量(例如 Observeble<number>
类型)。但是我无法在 outlet 组件中获取可观察变量。出现以下错误:NullInjectorError: No provider for [object Object]!
.
这是一个代码示例,我从 angular 文档 (angular.io/api/common/NgComponentOutlet) 中获得了这个模式并做了一些修改:
@Injectable()
export class Greeter {
suffix$: Observable<number> = null;
constructor(private _suffix$: Observable<number>) {
this.suffix$ = this._suffix$;
}
}
@Component({
selector: 'complete-component',
template: `Complete: {{ greeter.suffix$ | async }}`
})
export class CompleteComponent {
constructor(public greeter: Greeter) {
this.greeter.suffix$.subscribe(data => console.log('data', data));
// not working
}
}
@Component({
selector: 'ng-component-outlet-complete-example',
template: `
<ng-container *ngComponentOutlet="CompleteComponent;
injector: myInjector;"
})
export class NgTemplateOutletCompleteExample {
CompleteComponent = CompleteComponent;
myInjector: Injector;
suffix$: Observable<number> = of(3);
constructor(injector: Injector) {
this.myInjector =
Injector.create({providers: [{provide: Greeter, deps: [this.suffix$]}], parent: injector});
}
}
那么我怎样才能在 outlet 组件中获取和订阅这个 $suffix
变量。
P.S. 如果我将 NgTemplateOutletCompleteExample
提供到 deps
数组中并在可注入组件中获取 NgTemplateOutletCompleteExample.suffix$
Greeter
- 它会起作用。但问题是我有很多 NgTemplateOutletCompleteExample
组件,这对我来说无效。
对于动态注入接受输入并返回输出的组件,我遇到了类似的问题。 Angular 本身不支持动态组件上的 @Input()
和 @Output
。
您可以使用包 NgDynamicComponent:https://www.npmjs.com/package/ng-dynamic-component.
NgComponentOutlet 语法支持
该包支持 NgComponentOutlet 语法,您可以在此处看到:
https://www.npmjs.com/package/ng-dynamic-component#ngcomponentoutlet-support
从我从你的代码中看到的,这就是你所要求的:NgComponentOutlet + 输入支持。
用于更高级内容的自定义动态注入器
您还可以创建自定义注入器:https://www.npmjs.com/package/ng-dynamic-component#extra
最主要的是 Injector - 是一个静态注入器。因此,要在组件 oultet 中提供任何数据(或获取任何回调),我必须使用 useValue
而不是 deps
.
NgTemplateOutletCompleteExample
中的构造函数应该是这样的:
constructor(injector: Injector) {
this.myInjector =
Injector.create({providers: [{provide: Greeter, deps: [], useValue: {suffix$: this.suffix$}], parent: injector});
}
为了理解为什么会出现该错误,我建议您查看文档中的 Dependency Providers。
错误来自这里
Injector.create({providers: [{provide: Greeter, deps: [this.suffix$]}], parent: injector});
简而言之,deps
数组必须是有效DI令牌的列表并且没有为this.suffix$
配置令牌。
引用来源(Angular 8.0.0)
export interface FactorySansProvider {
/**
* A function to invoke to create a value for this `token`. The function is invoked with
* resolved values of `token`s in the `deps` field.
*/
useFactory: Function;
/**
* A list of `token`s which need to be resolved by the injector. The list of values is then
* used as arguments to the `useFactory` function.
*/
deps?: any[];
}
这是一种解决方法:
const OBS_TOKEN = new InjectionToken('obs');
@Injectable()
export class Greeter {
greeterProp = 'hello!';
constructor (@Inject(OBS_TOKEN) public suffix$: Observable<any>) {
console.log('[GREETER]', this.suffix$)
}
}
@Component({ /* ... */ })
export class NgTemplateOutletCompleteExample {
/* ... */
myInjector = Injector.create({
providers: [
{ provide: Greeter, deps: [OBS_TOKEN], },
{ provide: OBS_TOKEN, useValue: this.dummyObs$ },
],
parent: this.inj,
})
/* ... */
}
我需要为我的 ngComponentOutlet
使用某种 @Input()
装饰器。
但是Angular好像没有这个功能。相反,我想在出口组件中传递的所有内容都应通过 Injector
.
如果我想启动我想提供给内部注射器的东西,那很好 class。但我需要更深入地研究并在创建 Injector 步骤时提供某种可观察变量(例如 Observeble<number>
类型)。但是我无法在 outlet 组件中获取可观察变量。出现以下错误:NullInjectorError: No provider for [object Object]!
.
这是一个代码示例,我从 angular 文档 (angular.io/api/common/NgComponentOutlet) 中获得了这个模式并做了一些修改:
@Injectable()
export class Greeter {
suffix$: Observable<number> = null;
constructor(private _suffix$: Observable<number>) {
this.suffix$ = this._suffix$;
}
}
@Component({
selector: 'complete-component',
template: `Complete: {{ greeter.suffix$ | async }}`
})
export class CompleteComponent {
constructor(public greeter: Greeter) {
this.greeter.suffix$.subscribe(data => console.log('data', data));
// not working
}
}
@Component({
selector: 'ng-component-outlet-complete-example',
template: `
<ng-container *ngComponentOutlet="CompleteComponent;
injector: myInjector;"
})
export class NgTemplateOutletCompleteExample {
CompleteComponent = CompleteComponent;
myInjector: Injector;
suffix$: Observable<number> = of(3);
constructor(injector: Injector) {
this.myInjector =
Injector.create({providers: [{provide: Greeter, deps: [this.suffix$]}], parent: injector});
}
}
那么我怎样才能在 outlet 组件中获取和订阅这个 $suffix
变量。
P.S. 如果我将 NgTemplateOutletCompleteExample
提供到 deps
数组中并在可注入组件中获取 NgTemplateOutletCompleteExample.suffix$
Greeter
- 它会起作用。但问题是我有很多 NgTemplateOutletCompleteExample
组件,这对我来说无效。
对于动态注入接受输入并返回输出的组件,我遇到了类似的问题。 Angular 本身不支持动态组件上的 @Input()
和 @Output
。
您可以使用包 NgDynamicComponent:https://www.npmjs.com/package/ng-dynamic-component.
NgComponentOutlet 语法支持
该包支持 NgComponentOutlet 语法,您可以在此处看到: https://www.npmjs.com/package/ng-dynamic-component#ngcomponentoutlet-support
从我从你的代码中看到的,这就是你所要求的:NgComponentOutlet + 输入支持。
用于更高级内容的自定义动态注入器
您还可以创建自定义注入器:https://www.npmjs.com/package/ng-dynamic-component#extra
最主要的是 Injector - 是一个静态注入器。因此,要在组件 oultet 中提供任何数据(或获取任何回调),我必须使用 useValue
而不是 deps
.
NgTemplateOutletCompleteExample
中的构造函数应该是这样的:
constructor(injector: Injector) {
this.myInjector =
Injector.create({providers: [{provide: Greeter, deps: [], useValue: {suffix$: this.suffix$}], parent: injector});
}
为了理解为什么会出现该错误,我建议您查看文档中的 Dependency Providers。
错误来自这里
Injector.create({providers: [{provide: Greeter, deps: [this.suffix$]}], parent: injector});
简而言之,deps
数组必须是有效DI令牌的列表并且没有为this.suffix$
配置令牌。
引用来源(Angular 8.0.0)
export interface FactorySansProvider {
/**
* A function to invoke to create a value for this `token`. The function is invoked with
* resolved values of `token`s in the `deps` field.
*/
useFactory: Function;
/**
* A list of `token`s which need to be resolved by the injector. The list of values is then
* used as arguments to the `useFactory` function.
*/
deps?: any[];
}
这是一种解决方法:
const OBS_TOKEN = new InjectionToken('obs');
@Injectable()
export class Greeter {
greeterProp = 'hello!';
constructor (@Inject(OBS_TOKEN) public suffix$: Observable<any>) {
console.log('[GREETER]', this.suffix$)
}
}
@Component({ /* ... */ })
export class NgTemplateOutletCompleteExample {
/* ... */
myInjector = Injector.create({
providers: [
{ provide: Greeter, deps: [OBS_TOKEN], },
{ provide: OBS_TOKEN, useValue: this.dummyObs$ },
],
parent: this.inj,
})
/* ... */
}