Angular Material 2Stepperを使用して線形ステッパーをセットアップしました。
さまざまなコンポーネント(コンポーネント-a、コンポーネント-b、コンポーネント-c)のフォームがあります。私のメインコンテナコンポーネント(container-component)には、フォームが有効なときに各コンポーネントを「ステップスルー」する線形ステッパーが必要です。
ステッパーのstepControl
と通信して、正しく機能させるための何らかの機能はありますか?
ステッパーとStackBlitzバージョンのアプリケーションのドキュメントを添付しました。また、私が作業しているリポジトリへのリンクもあります。
マテリアルステッパーコンポーネント: https://material.angular.io/components/stepper/overview
StackBlitz: https://stackblitz.com/edit/angular-material2-issue-mjmu9u?file=app/app.component.ts
Github: https://github.com/sam11385
まったく同じ問題が発生し、数日間の試行錯誤の末、実用的な解決策が見つかりました。基本的に、ステップはそれぞれがフォームを定義するいくつかのコンポーネントに分割され、対応するstepControlが親にある必要があるため、子コンポーネントのFormGroupをステッパーを定義する親コンポーネントに送信する必要があります。 FormGroupを作成した後、イベントを発行し、親にそのイベントをリッスンさせ、FormGroupをそのイベントに渡します。これをすべての子に適用して、それぞれに個別のイベントを作成し、各エミッターの親に個別のリスナーを作成できます。
イベントを宣言する
@Output() notify: EventEmitter<FormGroup> = new EventEmitter<FormGroup>();
formGroupを親コンポーネントに発行します
this.notify.emit(this.myFormGroup);
Component(.ts)に、フォームグループを受信して設定する関数を追加します。
myFormGroup: FormGroup;
onNotify(formGroup: FormGroup): void {
this.myFormGroup = formGroup;
}
HTMLで、通知リスナーを追加します。
<mat-step [completed]="false" [stepControl]="myFormGroup">
<ng-template matStepLabel>Step 1</ng-template>
<app-child (notify)='onNotify($event)'></app-child>
</mat-step>
ネストされたコンポーネントの説明: https://www.themarketingtechnologist.co/building-nested-components-in-angular-2/
上記の答えは的を射ていますが、特定のユースケースでこの実装でいくつかのより深い問題に遭遇したため、共有サービスで解決しました。
form-management.service.ts
import { Injectable } from '@angular/core';
import { FormGroup } from '@angular/forms';
import { Observable } from 'rxjs/Observable';
import { Subject } from 'rxjs/Subject';
@Injectable()
export class FormManagementService {
private formSource: Subject<FormGroup> = new Subject();
locationForm: Observable<FormGroup> = this.formSource.asObservable();
formReady(form: FormGroup): void {
this.formSource.next(form);
}
}
parent.component.ts
import { Component } from '@angular/core';
import { FormGroup } from '@angular/forms';
import { FormManagementService } from './form-management.service';
@Component({
....
providers: [ FormManagementService ]
})
export class ParentComponent {
form: FormGroup;
constructor(private formManagementService: FormManagementService) {
this.formManagementService.locationForm.subscribe(form => this.form = form);
}
}
ここでは、共有サービスの変更をサブスクライブしていることに注意してください。これにより、必要なときにフォームがコンポーネントに渡されます。親コンポーネントがフォームを受信すると、FormGroupにデータが入力されます。
また、コンポーネントデコレータの一部としてここで共有サービスを提供していることにも注意してください。コードが構造化されている場合は、機能モジュールで提供することもできます。
child.component.ts
import { Component } from '@angular/core';
import { FormGroup, FormBuilder } from '@angular/forms';
import { FormManagementService } from './form-management.service';
@Component({ ... })
export class ChildComponent {
form: FormGroup;
constructor(private formManagementService: FormManagementService,
private formBuilder: FormBuilder) {
this.form = this.formBuilder.group({});
this.formManagementService.formReady(this.form);
}
}
ここで子コンポーネントでフォームを初期化し、共有サービスを介してプッシュします。これにより、フォームが親コンポーネントに入力されます。
コンストラクター以外の場所でこれを実行した場合、ExpressionChangedAfterItHasBeenCheckedError
でこれを実行したときに、ngAfterContentInit
、evenに遭遇したことに注意してください。おそらく、他の誰かがこれを解決するために私のソリューションをさらに進歩させるでしょう。
とにかく、この問題が数週間私を悩ませていたので、これがそこにいる誰かの助けになることを願っています。