如何在 angular 5 中启用 "as syntax" 创建自定义指令?
How to create custom directive with enabled "as syntax" in angular 5?
在 angular 5 中有 ngIf
指令的内置功能 - as syntax
。您可以在此处找到示例 https://toddmotto.com/angular-ngif-async-pipe.
在下面的示例中,user$
是一个可观察对象。
<div *ngIf="(user$ | async) as user; else loading">
<user-profile
[user]="user.profile">
</user-profile>
<user-messages
[user]="user.messages">
</user-messages>
</div>
<ng-template #loading>
Loading stuff...
</ng-template>
我创建了自己的指令,用加载微调器替换元素的内容,我想启用传递可观察值作为输入,请参见下面的代码。
@Directive({ selector: '[appLoadingData]' })
export class LoadingDataDirective {
constructor(
private templateRef: TemplateRef<any>,
private viewContainerRef: ViewContainerRef,
private componentFactoryResolver: ComponentFactoryResolver
) { }
@Input()
set appLoadingData(data: any) {
if (data != null) {
if (data.subscribe) {
this.addLoadingPlaceholder();
data.subscribe(() => {
setTimeout(() => this.addView(), 0);
});
} else {
this.addView();
}
} else {
this.addLoadingPlaceholder();
}
}
private addView() {
this.viewContainerRef.clear();
this.viewContainerRef.createEmbeddedView(this.templateRef);
}
private addLoadingPlaceholder() {
this.viewContainerRef.clear();
const loadingComponentFactory = this.componentFactoryResolver.resolveComponentFactory(LoadingDataComponent);
this.viewContainerRef.createComponent(loadingComponentFactory);
}
}
而我想用下一种方式
<ng-container *ngFor="let chartConfig of chartsConfigs">
<div class="chart-wrapper"
*appLoadingData="(chartConfig.chartGroups$ | async) as groups">
<chart-summary [chartData]="groups"
[chartOptionsName]="chartConfig.chartType">
</chart-summary>
</div>
</ng-container>
或理想情况下 *appLoadingData="chartConfig.chartGroups$ as groups"
没有 as 语法(*appLoadingData="chartConfig.chartGroups$ | async"
和 [chartData]="chartConfig.chartGroups$ | async"
),在我的加载程序关闭后有延迟,我认为这是因为在 addView()
in 指令中,异步管道调用了第二个时间。我想像 ngIf 指令一样实现 as syntax
。我试过这样使用它: *appLoadingData="(chartConfig.chartGroups$ | async) as groups"
,但不幸的是在这种情况下 groups
总是 undefined
.
如何在自定义指令中实现as syntax
?
您可以看到他们正在使用 _context
变量。 https://github.com/angular/angular/blob/master/packages/common/src/directives/ng_if.ts
另见@yurzui 的回答。
我的最终结果:
export class LoadingDataDirective {
context: any = {};
constructor(
private templateRef: TemplateRef<any>,
private viewContainerRef: ViewContainerRef,
private componentFactoryResolver: ComponentFactoryResolver
) { }
@Input()
set appLoadingData(data: any) {
if (data != null) {
if (this.isObservable(data)) {
this.addLoadingPlaceholder();
const subscription = data.subscribe((observableResult: any) => {
this.addView(observableResult);
subscription.unsubscribe();
});
} else {
this.addView(data);
}
} else {
this.addLoadingPlaceholder();
}
}
private addView(contextData: any) {
this.context.$implicit = this.context.appLoadingData = contextData;
this.viewContainerRef.clear();
this.viewContainerRef.createEmbeddedView(this.templateRef, this.context);
}
private addLoadingPlaceholder() {
this.viewContainerRef.clear();
const loadingComponentFactory = this.componentFactoryResolver.resolveComponentFactory(LoadingDataComponent);
this.viewContainerRef.createComponent(loadingComponentFactory);
}
private isObservable(data: any): boolean {
return !!data.subscribe;
}
}
chartConfig.charGroup$
- 是可观察的
<ng-container *ngFor="let chartConfig of chartsConfigs">
<div class="chart-wrapper"
*appLoadingData="chartConfig.chartGroups$ as groups">
<chart-summary [chartData]="groups"
[chartOptionsName]="chartConfig.chartType">
</chart-summary>
</div>
</ng-container>
在 angular 5 中有 ngIf
指令的内置功能 - as syntax
。您可以在此处找到示例 https://toddmotto.com/angular-ngif-async-pipe.
在下面的示例中,user$
是一个可观察对象。
<div *ngIf="(user$ | async) as user; else loading">
<user-profile
[user]="user.profile">
</user-profile>
<user-messages
[user]="user.messages">
</user-messages>
</div>
<ng-template #loading>
Loading stuff...
</ng-template>
我创建了自己的指令,用加载微调器替换元素的内容,我想启用传递可观察值作为输入,请参见下面的代码。
@Directive({ selector: '[appLoadingData]' })
export class LoadingDataDirective {
constructor(
private templateRef: TemplateRef<any>,
private viewContainerRef: ViewContainerRef,
private componentFactoryResolver: ComponentFactoryResolver
) { }
@Input()
set appLoadingData(data: any) {
if (data != null) {
if (data.subscribe) {
this.addLoadingPlaceholder();
data.subscribe(() => {
setTimeout(() => this.addView(), 0);
});
} else {
this.addView();
}
} else {
this.addLoadingPlaceholder();
}
}
private addView() {
this.viewContainerRef.clear();
this.viewContainerRef.createEmbeddedView(this.templateRef);
}
private addLoadingPlaceholder() {
this.viewContainerRef.clear();
const loadingComponentFactory = this.componentFactoryResolver.resolveComponentFactory(LoadingDataComponent);
this.viewContainerRef.createComponent(loadingComponentFactory);
}
}
而我想用下一种方式
<ng-container *ngFor="let chartConfig of chartsConfigs">
<div class="chart-wrapper"
*appLoadingData="(chartConfig.chartGroups$ | async) as groups">
<chart-summary [chartData]="groups"
[chartOptionsName]="chartConfig.chartType">
</chart-summary>
</div>
</ng-container>
或理想情况下 *appLoadingData="chartConfig.chartGroups$ as groups"
没有 as 语法(*appLoadingData="chartConfig.chartGroups$ | async"
和 [chartData]="chartConfig.chartGroups$ | async"
),在我的加载程序关闭后有延迟,我认为这是因为在 addView()
in 指令中,异步管道调用了第二个时间。我想像 ngIf 指令一样实现 as syntax
。我试过这样使用它: *appLoadingData="(chartConfig.chartGroups$ | async) as groups"
,但不幸的是在这种情况下 groups
总是 undefined
.
如何在自定义指令中实现as syntax
?
您可以看到他们正在使用 _context
变量。 https://github.com/angular/angular/blob/master/packages/common/src/directives/ng_if.ts
另见@yurzui 的回答。
我的最终结果:
export class LoadingDataDirective {
context: any = {};
constructor(
private templateRef: TemplateRef<any>,
private viewContainerRef: ViewContainerRef,
private componentFactoryResolver: ComponentFactoryResolver
) { }
@Input()
set appLoadingData(data: any) {
if (data != null) {
if (this.isObservable(data)) {
this.addLoadingPlaceholder();
const subscription = data.subscribe((observableResult: any) => {
this.addView(observableResult);
subscription.unsubscribe();
});
} else {
this.addView(data);
}
} else {
this.addLoadingPlaceholder();
}
}
private addView(contextData: any) {
this.context.$implicit = this.context.appLoadingData = contextData;
this.viewContainerRef.clear();
this.viewContainerRef.createEmbeddedView(this.templateRef, this.context);
}
private addLoadingPlaceholder() {
this.viewContainerRef.clear();
const loadingComponentFactory = this.componentFactoryResolver.resolveComponentFactory(LoadingDataComponent);
this.viewContainerRef.createComponent(loadingComponentFactory);
}
private isObservable(data: any): boolean {
return !!data.subscribe;
}
}
chartConfig.charGroup$
- 是可观察的
<ng-container *ngFor="let chartConfig of chartsConfigs">
<div class="chart-wrapper"
*appLoadingData="chartConfig.chartGroups$ as groups">
<chart-summary [chartData]="groups"
[chartOptionsName]="chartConfig.chartType">
</chart-summary>
</div>
</ng-container>