如何根据 Angular 11 中的 child 值更新 parent HTML 而不会导致 NG0100?
How to update parent HTML based on child value in Angular 11 without causing NG0100?
我正在努力寻找一种有效且不会引发 NG0100
错误的解决方案。 https://angular.io/errors/NG0100
当单击 header 元素时,我的 AppComponent 中有创建 child 组件的逻辑。当 child 组件被创建时,它会启动一系列需要一些时间来加载的数据调用。在那段时间里,我显示了一个加载栏。目前,用户可以一次又一次地点击 App HTML 中的 header 元素,这会导致选择的 child 组件被一次又一次地创建和销毁。这也具有多次数据调用的效果。
理想情况下,我想禁用 parent 组件上的点击操作并更改不透明度,以便用户知道它在加载时被禁用。我确实通过以下方式实现了这一点:
- AppComponent 中的静态方法和静态变量
- @child 组件上的输入法以 Objects 作为输入
- @child 组件上的输出方法,原始值作为输出
但是,所有这些解决方案都在控制台中引发了 NG0100: Expression has changed after it was checked
错误。我不想实施一个有效但会抛出错误的 hacky 解决方案。什么是正确的方法?
certificationView: View = {
shouldEnable: true,
shouldRender: false
}
toggleViewShouldRender(view: View): void {
if (view.shouldEnable) {
view.shouldRender = !view.shouldRender;
}
}
app.component.ts
<div>
<mat-card
[ngClass]="{'disabled': !certificationView.shouldEnable}"
(click)="toggleViewShouldRender(certificationView)"
>
Certifications
</mat-card>
<app-certifications *ngIf="certificationView.shouldRender"></app-certifications>
</div>
app.component.html
ngOnInit(): void {
this.facade.retrieve()
.pipe(
takeUntil(this.destroyed$),
filter(state => !!state?.data)
)
.subscribe(state => {
this.state = state;
});
}
child.component.ts
注意:我删除了导致错误的所有逻辑。干净利落的执行对我来说比这个功能更重要。我之前在订阅数据服务之前以及订阅内部修改了 ngOnInit 中的 View.shouldEnable 属性。
例如,
<div>
<mat-card
[ngClass]="{'disabled': !certificationView.shouldEnable}"
(click)="toggleViewShouldRender(certificationView)"
>
Certifications
</mat-card>
<app-certifications
*ngIf="certificationView.shouldRender"
[(shouldEnable)]="certificationView.shouldEnable"
>
</app-certifications>
</div>
app.component.html
@Input shouldEnable: boolean;
@Output shouldEnableChange = new EventEmitter<boolean>();
ngOnInit(): void {
// disable header in parent
this.shouldEnableChange.emit(false);
// load data
this.facade.retrieve()
.pipe(
takeUntil(this.destroyed$),
filter(state => !!state?.data)
)
.subscribe(state => {
this.state = state;
// enable header in parent
this.shouldEnableChange.emit(true);
});
}
child.component.ts
您可以使用 InjectionToken
将 parent 的引用转发给 child 组件。然后你可以在 child.
的 parent 上触发 methods
或设置 properties
首先你会创建一个注入令牌,我会把它放在它自己的文件中,比如 tokens.ts
。
export const PARENT_COMPONENT = new InjectionToken<ParentComponent>('MyParentInjectionToken')
接下来,您将像这样在 parent 组件上提供令牌。然后它将自己转发给它的 children(见下一个代码块)。
@Comonent({
providers: [{
provide: PARENT_COMPONENT,
useExisting: forwardRef(() => ParentComponent)
}]
})
export class ParentComponent {
valueToSet = false;
setValue(val: boolean) {
this.valueToSet = val
}
}
这是我们 @Inject()
将 parent 放入构造函数的地方,因此我们可以访问。有时并不总是 parent 在这种情况下你可以使用 @Optional() @Inject()
.
@Component({
template: '<button (click)="doSomething()">Click Me</button>'
})
export class ChildComponent {
constructor(
@Inject(PARENT_COMPONENT) parentComponent: ParentComponent
){}
doSomething() {
this.parentCompnent.setValue(true);
}
}
我正在努力寻找一种有效且不会引发 NG0100
错误的解决方案。 https://angular.io/errors/NG0100
当单击 header 元素时,我的 AppComponent 中有创建 child 组件的逻辑。当 child 组件被创建时,它会启动一系列需要一些时间来加载的数据调用。在那段时间里,我显示了一个加载栏。目前,用户可以一次又一次地点击 App HTML 中的 header 元素,这会导致选择的 child 组件被一次又一次地创建和销毁。这也具有多次数据调用的效果。
理想情况下,我想禁用 parent 组件上的点击操作并更改不透明度,以便用户知道它在加载时被禁用。我确实通过以下方式实现了这一点:
- AppComponent 中的静态方法和静态变量
- @child 组件上的输入法以 Objects 作为输入
- @child 组件上的输出方法,原始值作为输出
但是,所有这些解决方案都在控制台中引发了 NG0100: Expression has changed after it was checked
错误。我不想实施一个有效但会抛出错误的 hacky 解决方案。什么是正确的方法?
certificationView: View = {
shouldEnable: true,
shouldRender: false
}
toggleViewShouldRender(view: View): void {
if (view.shouldEnable) {
view.shouldRender = !view.shouldRender;
}
}
app.component.ts
<div>
<mat-card
[ngClass]="{'disabled': !certificationView.shouldEnable}"
(click)="toggleViewShouldRender(certificationView)"
>
Certifications
</mat-card>
<app-certifications *ngIf="certificationView.shouldRender"></app-certifications>
</div>
app.component.html
ngOnInit(): void {
this.facade.retrieve()
.pipe(
takeUntil(this.destroyed$),
filter(state => !!state?.data)
)
.subscribe(state => {
this.state = state;
});
}
child.component.ts
注意:我删除了导致错误的所有逻辑。干净利落的执行对我来说比这个功能更重要。我之前在订阅数据服务之前以及订阅内部修改了 ngOnInit 中的 View.shouldEnable 属性。
例如,
<div>
<mat-card
[ngClass]="{'disabled': !certificationView.shouldEnable}"
(click)="toggleViewShouldRender(certificationView)"
>
Certifications
</mat-card>
<app-certifications
*ngIf="certificationView.shouldRender"
[(shouldEnable)]="certificationView.shouldEnable"
>
</app-certifications>
</div>
app.component.html
@Input shouldEnable: boolean;
@Output shouldEnableChange = new EventEmitter<boolean>();
ngOnInit(): void {
// disable header in parent
this.shouldEnableChange.emit(false);
// load data
this.facade.retrieve()
.pipe(
takeUntil(this.destroyed$),
filter(state => !!state?.data)
)
.subscribe(state => {
this.state = state;
// enable header in parent
this.shouldEnableChange.emit(true);
});
}
child.component.ts
您可以使用 InjectionToken
将 parent 的引用转发给 child 组件。然后你可以在 child.
methods
或设置 properties
首先你会创建一个注入令牌,我会把它放在它自己的文件中,比如 tokens.ts
。
export const PARENT_COMPONENT = new InjectionToken<ParentComponent>('MyParentInjectionToken')
接下来,您将像这样在 parent 组件上提供令牌。然后它将自己转发给它的 children(见下一个代码块)。
@Comonent({
providers: [{
provide: PARENT_COMPONENT,
useExisting: forwardRef(() => ParentComponent)
}]
})
export class ParentComponent {
valueToSet = false;
setValue(val: boolean) {
this.valueToSet = val
}
}
这是我们 @Inject()
将 parent 放入构造函数的地方,因此我们可以访问。有时并不总是 parent 在这种情况下你可以使用 @Optional() @Inject()
.
@Component({
template: '<button (click)="doSomething()">Click Me</button>'
})
export class ChildComponent {
constructor(
@Inject(PARENT_COMPONENT) parentComponent: ParentComponent
){}
doSomething() {
this.parentCompnent.setValue(true);
}
}