Angular Material Stepper 每个步骤都有单独的组件 - ExpressionChangedAfterItHasBeenCheckedError
Angular Material Stepper with Separate Component for each step - ExpressionChangedAfterItHasBeenCheckedError
我有一个 material 步进器,步进器的每一步都有表格。在那里,每个步骤都应由与其关联的表单控制。
尽管这个问题已经在 SO 中提出,但这些问题的答案并不能解决我的问题。所以我问。
Parent HTML
<mat-horizontal-stepper linear #stepper>
<mat-step [stepControl]="frmStepOne">
<ng-template matStepLabel>Step One Details</ng-template>
<app-first-step #stepOne></app-first-step>
</mat-step>
<mat-step [stepControl]="frmStepTwo">
<ng-template matStepLabel>Step Two Details</ng-template>
<app-second-step #stepTwo></app-second-step>
</mat-step>
</mat-horizontal-stepper>
在我的 parent 组件中,我有以下内容。
@ViewChild('stepOne') stepOneComponent: FirstStepComponent;
@ViewChild('stepTwo') stepTwoComponent: SecondStepComponent;
get frmStepOne() {
return this.stepOneComponent ? this.stepOneComponent.frmStepOne : null;
}
get frmStepTwo() {
return this.stepTwoComponent ? this.stepTwoComponent.frmStepTwo : null;
}
我的Childclass组件
frmStepOne: FormGroup;
constructor(private formBuilder: FormBuilder) {
this.frmStepOne = this.formBuilder.group({
name: ['', Validators.required]
});
}
Child Class HTML
<mat-card>
<form [formGroup]="frmStepOne">
<mat-form-field>
<input matInput formControlName="name" matInput placeholder="Name" required>
</mat-form-field>
<mat-card-actions>
<button mat-raised-button matStepperNext class="nav-btn pull-right">Next</button>
</mat-card-actions>
</form>
</mat-card>
现在,当我 运行 应用程序时,在控制台中,我看到以下内容。
ERROR Error: ExpressionChangedAfterItHasBeenCheckedError: Expression
has changed after it was checked. Previous value: 'stepControl: null'.
Current value: 'stepControl: [object Object]'.
正如我之前提到的,在 SO 中有相同的讨论。例如,回答和以下链接问题的评论建议将表单初始化移至构造函数,而不是将其放在 onInit 中。我已经这样做了。
但是,我仍然遇到错误。
这是我在 Stackblitz 上的项目 - https://stackblitz.com/github/vigamage/stepper-component-wise
有人可以建议如何解决这个问题吗?
谢谢..
只需将导致此错误的变量更改为 Observable
并使用 delay(0)
operator
将其更改为 pipe
这是一个 link 有效的解决方案 - 没有错误,也不需要使用更改检测。
这里有一个例子
假设我在 html
模板中使用类型 string
的变量 name
,它导致了上述错误。
<div>{{ name }}</div> // BOOM ERROR why?
因为一开始name
是个东西,在angular检查过后改了。
所以要解决这个问题..首先将 name
更改为 Observable
,例如 name$
name$: Observable<string>; // name$ replaces name
private myName$ = new BehaviorSubject<string>("");
myNameListener$: Observable<string> = this.myName$.asObservable();
myName(name: string) {
this.myName$.next(name)
}
现在 ngOnInit()
只听那个 Observable
ngOnInit() {
this.name$ = this.myNameListener$.pipe(
delay(0)
)
}
使用 async
管道
在您的 html
模板中订阅 Observable
<div *ngIf=" (name$ | async) as name ">{{ name }}</div> // render your variable
现在将您的实际数据传递到任何您想要的可观察对象。
this.myName(data);
这是一个 link 有效的解决方案 - 没有错误,也不需要使用更改检测。
祝你好运!
基本上,angular 在已经将两个值的值设置为 null
之后检测到变化。因此,您需要明确告诉 angular 它应该 运行 更改检测。 Check out this demo code
我删除了使用 get
的逻辑,因为直接从 HTML 调用函数是一种不好的做法。它会被多次调用。尝试将控制台日志放入您的代码中并查看。
我用 ngAfterViewInit
和 ChangeDetectorRef
来通知。
export class AppComponent implements AfterViewInit {
title = 'mat-stepper';
form1: FormGroup;
form2: FormGroup;
@ViewChild('stepOne') stepOneComponent: FirstStepComponent;
@ViewChild('stepTwo') stepTwoComponent: SecondStepComponent;
constructor(private cdr :ChangeDetectorRef){}
ngAfterViewInit(){
this.form1 = this.stepOneComponent.frmStepOne;
this.form2 = this.stepTwoComponent.frmStepTwo
this.cdr.detectChanges();
}
}
这将解决错误
处理这个问题的一个非常简单的方法是在子模板中声明表单组,在父模板中,您可以引用它!这样做的主要好处是它非常安全,并且比所有其他选项都干净得多。
<mat-step [stepControl]="step1.step1Form">
<app-step1 #step1></app-step1>
</mat-step>
我有一个 material 步进器,步进器的每一步都有表格。在那里,每个步骤都应由与其关联的表单控制。
尽管这个问题已经在 SO 中提出,但这些问题的答案并不能解决我的问题。所以我问。
Parent HTML
<mat-horizontal-stepper linear #stepper>
<mat-step [stepControl]="frmStepOne">
<ng-template matStepLabel>Step One Details</ng-template>
<app-first-step #stepOne></app-first-step>
</mat-step>
<mat-step [stepControl]="frmStepTwo">
<ng-template matStepLabel>Step Two Details</ng-template>
<app-second-step #stepTwo></app-second-step>
</mat-step>
</mat-horizontal-stepper>
在我的 parent 组件中,我有以下内容。
@ViewChild('stepOne') stepOneComponent: FirstStepComponent;
@ViewChild('stepTwo') stepTwoComponent: SecondStepComponent;
get frmStepOne() {
return this.stepOneComponent ? this.stepOneComponent.frmStepOne : null;
}
get frmStepTwo() {
return this.stepTwoComponent ? this.stepTwoComponent.frmStepTwo : null;
}
我的Childclass组件
frmStepOne: FormGroup;
constructor(private formBuilder: FormBuilder) {
this.frmStepOne = this.formBuilder.group({
name: ['', Validators.required]
});
}
Child Class HTML
<mat-card>
<form [formGroup]="frmStepOne">
<mat-form-field>
<input matInput formControlName="name" matInput placeholder="Name" required>
</mat-form-field>
<mat-card-actions>
<button mat-raised-button matStepperNext class="nav-btn pull-right">Next</button>
</mat-card-actions>
</form>
</mat-card>
现在,当我 运行 应用程序时,在控制台中,我看到以下内容。
ERROR Error: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'stepControl: null'. Current value: 'stepControl: [object Object]'.
正如我之前提到的,在 SO 中有相同的讨论。例如,回答和以下链接问题的评论建议将表单初始化移至构造函数,而不是将其放在 onInit 中。我已经这样做了。
但是,我仍然遇到错误。
这是我在 Stackblitz 上的项目 - https://stackblitz.com/github/vigamage/stepper-component-wise
有人可以建议如何解决这个问题吗?
谢谢..
只需将导致此错误的变量更改为 Observable
并使用 delay(0)
operator
pipe
这是一个 link 有效的解决方案 - 没有错误,也不需要使用更改检测。
这里有一个例子
假设我在 html
模板中使用类型 string
的变量 name
,它导致了上述错误。
<div>{{ name }}</div> // BOOM ERROR why?
因为一开始name
是个东西,在angular检查过后改了。
所以要解决这个问题..首先将 name
更改为 Observable
,例如 name$
name$: Observable<string>; // name$ replaces name
private myName$ = new BehaviorSubject<string>("");
myNameListener$: Observable<string> = this.myName$.asObservable();
myName(name: string) {
this.myName$.next(name)
}
现在 ngOnInit()
只听那个 Observable
ngOnInit() {
this.name$ = this.myNameListener$.pipe(
delay(0)
)
}
使用 async
管道
html
模板中订阅 Observable
<div *ngIf=" (name$ | async) as name ">{{ name }}</div> // render your variable
现在将您的实际数据传递到任何您想要的可观察对象。
this.myName(data);
这是一个 link 有效的解决方案 - 没有错误,也不需要使用更改检测。
祝你好运!
基本上,angular 在已经将两个值的值设置为 null
之后检测到变化。因此,您需要明确告诉 angular 它应该 运行 更改检测。 Check out this demo code
我删除了使用 get
的逻辑,因为直接从 HTML 调用函数是一种不好的做法。它会被多次调用。尝试将控制台日志放入您的代码中并查看。
我用 ngAfterViewInit
和 ChangeDetectorRef
来通知。
export class AppComponent implements AfterViewInit {
title = 'mat-stepper';
form1: FormGroup;
form2: FormGroup;
@ViewChild('stepOne') stepOneComponent: FirstStepComponent;
@ViewChild('stepTwo') stepTwoComponent: SecondStepComponent;
constructor(private cdr :ChangeDetectorRef){}
ngAfterViewInit(){
this.form1 = this.stepOneComponent.frmStepOne;
this.form2 = this.stepTwoComponent.frmStepTwo
this.cdr.detectChanges();
}
}
这将解决错误
处理这个问题的一个非常简单的方法是在子模板中声明表单组,在父模板中,您可以引用它!这样做的主要好处是它非常安全,并且比所有其他选项都干净得多。
<mat-step [stepControl]="step1.step1Form">
<app-step1 #step1></app-step1>
</mat-step>