Я работаю над угловым проектом, который имеет следующую ситуацию: есть один компонент (ClientViewComponent), который содержит:
- Сводка всей клиентской формы в виде меток (ClientOverviewComponent);
- Различные «подформы», с помощью которых пользователь может переключаться между ними для редактирования (для простоты, давайте сосредоточимся только на одной, называемой ClientGeneralComponent);
Только одна из нихподформы отображаются одновременно для редактирования, но обзор отображает значения всех входных данных в подформах в режиме реального времени.
Так что это то, что существует сейчас (упрощено, чтобы показывать только частипроценты):
ClientViewComponent HTML
<div class="container overview-container">
<h2>Client Overview</h2>
<client-overview
[data]="clientOverviewData"
[generalGroup]="clientForm.controls['generalGroup']"
(editFrame)="editFrame($event)">
</client-overview>
</div>
<div *ngIf="(currentFrame$ | async)" class="container part-container">
<h2>Please choose: </h2>
<client-general
*ngIf="(currentFrame$ | async).code === 'general'" [data]="clientGeneralData" [formGroup]="clientForm.controls['generalGroup']">
</client-general>
</div>
ClientViewComponent TS
ngOnInit() {
this.clientForm = this.fb.group({
generalGroup: this.fb.group({
name: ['', [Validators.required, Validators.maxLength(256)]],
code: ['', [Validators.required, Validators.maxLength(32)]],
addressGroup: this.fb.group({
address: ['', [Validators.required, Validators.maxLength(512)]],
address2: ['', [Validators.maxLength(512)]],
city: ['', [Validators.required, Validators.maxLength(256)]],
state: ['', [Validators.required, Validators.maxLength(64)]],
zipCode: ['', [Validators.required, Validators.maxLength(64)]],
country: ['', [Validators.required]],
})
})
});
}
ClientOverviewHTML
<div class="span-container">
<span [ngClass]="{ 'modified-value' : !isNew && generalGroup.controls['name'].dirty }">* Client Name: {{generalGroup.controls['name'].value}}</span>
<span [ngClass]="{ 'modified-value' : !isNew && generalGroup.controls['code'].dirty }">* Client Code: {{generalGroup.controls['code'].value}}</span>
<span [ngClass]="{ 'modified-value' : !isNew && addressGroup.controls['address'].dirty }">* Address: {{addressGroup.controls['address'].value}}</span>
<span [ngClass]="{ 'modified-value' : !isNew && addressGroup.controls['address2'].dirty }">Address #2: {{addressGroup.controls['address2'].value}}</span>
<span [ngClass]="{ 'modified-value' : !isNew && addressGroup.controls['city'].dirty }">* City: {{addressGroup.controls['city'].value}}</span>
<span [ngClass]="{ 'modified-value' : !isNew && addressGroup.controls['state'].dirty }">* State: {{addressGroup.controls['state'].value}}</span>
<span [ngClass]="{ 'modified-value' : !isNew && addressGroup.controls['country'].dirty }">* Country: {{country}}</span>
<span [ngClass]="{ 'modified-value' : !isNew && addressGroup.controls['zipCode'].dirty }">* Zip Code: {{addressGroup.controls['zipCode'].value}}</span>
</div>
ClientOverviewComponent TS
export class ClientOverviewComponent implements OnInit {
@Input('data')
set Data(value: ClientOverviewData) {
this.setData(value);
}
generalGroup: FormGroup;
addressGroup: FormGroup;
@Input('generalGroup')
set GeneralGroup(value: FormGroup) {
this.generalGroup = value;
this.addressGroup = value.get('addressGroup') as FormGroup;
this.refreshClientValues();
}
HTML ClientGeneralComponent представляет собой обычную форму с formGroup и вводит данные с соответствующей formControlName
ClientGeneralComponent TS
export class ClientGeneralComponent implements OnInit {
@Input('data')
set Data(value: ClientGeneralData) {
this.setData(value);
}
formGroup: FormGroup;
addressGroup: FormGroup;
@Input('formGroup')
set FormGroup(value: FormGroup){
this.formGroup = value;
this.addressGroup = value.get('addressGroup') as FormGroup;
}
Теперь все это работает отлично.Полная форма работает как задумано, пользователь заполняет входные данные для компонента General, а значения отображаются в обзоре в режиме реального времени.Вопрос встал, когда я начал делать модульные тесты для компонентов.Проблема в том, что для тестового класса для ClientGeneralComponent мне нужно снова объявить группы форм и элементы управления, так же, как это делается в коде ClientViewComponent.Моя идея состояла в том, что, если бы я мог переместить инициализацию общей формы из ClientViewComponent в ClientGeneralComponent (который фактически содержит элементы управления), не было бы необходимости копировать код инициализации формы в тестовом классе, например:
beforeEach(() => {
fixture = TestBed.createComponent(ClientGeneralComponent);
component = fixture.componentInstance;
component.formGroup = fb.group({
name: ['', [Validators.required, Validators.maxLength(256)]],
code: ['', [Validators.required, Validators.maxLength(32)]],
addressGroup: fb.group({
address: ['', [Validators.required, Validators.maxLength(512)]],
address2: ['', [Validators.maxLength(512)]],
city: ['', [Validators.required, Validators.maxLength(256)]],
state: ['', [Validators.required, Validators.maxLength(64)]],
zipCode: ['', [Validators.required, Validators.maxLength(64)]],
country: ['', [Validators.required]]
})
});
fixture.detectChanges();
});
Но если я перенесу код инициализации общей формы в дочернюю форму, я начну получать ошибки «не могу прочитать свойство неопределенных» в компоненте Overview, поскольку он не инициализировал свойство «generalGroup» и его элементы управления.Поэтому у меня вопрос: есть ли способ сделать это, инициализировать группу форм в дочернем компоненте, к которому она принадлежит, и при этом иметь возможность связать ее в родительской форме.
Спасибо за любую помощь!