Вход

Просмотр полной версии : Связывание данных и состояния формы


shtangen
22.11.2019, 11:46
Здравствуйте, вопрос заключается в следующем: я отслеживаю изменения в форме. И есть несколько вариантов решения:

1. Подписываемся на изменения во всей форме. В этом случае, при возникновении события необходимо проверить всю форму и в измененное поле внести новое значение.

formSubm: Subscription;
componentForm: FormGroup;
componentData;

initState() {
this.componentForm = this.formBuilder.group({
code: new FormControl(""),
name: new FormControl("", [Validators.required),
date_modify: new FormControl(null),
});
}
ngOnInit() {
this.initState();
this.formSubm = this.componentForm.valueChanges
.subscribe(value => {
this.applyFormValues(value)
});
}

applyFormValues(item) {
Object.keys(item).forEach(key => {
if (this.componentData[key] != item[key])
this.componentData[key] = item[key];
});
}

ngOnDestroy() {
if (this.formSubm) {
this.formSubm.unsubscribe();
}
}


<form [formGroup]="componentForm" (ngSubmit)="formSubmit()">
<div>
<mat-form-field>
<input formControlName="code" matInput>
</mat-form-field>
<mat-form-field>
<input formControlName="name" matInput>
</mat-form-field>
<mat-form-field>
<input formControlName="date_modify" matInput>
</mat-form-field>
</div>
<button type="submit">
<ng-template>Сохранить</ng-template>
</button>
</form>


Второе решение, подписываться на изменения каждого из полей. При этом инициализацию, конечно, можно вогнать в цикл и при выходе из компонента отписываться от всех подписок, но волнует вопрос большого количества подписок.


ngOnInit() {
this.$s1 = this.componentForm.get('name').valueChanges.subscr ibe(res => {
this.ctrl.name.setValue(res, { emitEvent: false });
this.componentData['name'] = res;
});
this.$s2 = this.componentForm.get('code').valueChanges.subscr ibe(res => {
this.ctrl.code.setValue(res, { emitEvent: false });
this.componentData['code'] = res;
});

this.$s3 = this.componentForm.get('date_modify').valueChanges .subscribe(res =>
{this.ctrl.date_modify.setValue(res, { emitEvent: false });
this.componentData['date_modify'] = res;
});
}


Третий вариант -- создать одну универсальную функцию и вешать ее как обработчик:

<mat-form-field>
<mat-label>Код</mat-label>
<input formControlName="code" matInput (keyup)="onChange($event, 'code')">
</mat-form-field>



onChange(e: KeyboardEvent, field: string) {
if (e.key == "Enter") return false;
this.componentForm.controls[field].setValue((<HTMLInputElement>e.target).value);
this.componentData[field] = (<HTMLInputElement>e.target).value;
}


Какой вариант по вашему более оптимален с точки зрения производительности?

destus
25.11.2019, 06:19
shtangen,
зачем всё это писать в переменную componentData, если это же самое хранится в componentForm.value ?

shtangen
25.11.2019, 15:27
В componentData хранится определенный тип

componentData = new PostTemplate(<IPostTemplate>{});

ngOnInit() {
this.ctrl = this.componentForm.controls;
this.dataService.getItem<PostTemplate>(this.currId)
.subscribe((data: PostTemplate) => {
this.componentData = new PostTemplate(data);
this.ctrl.code.setValue(data.code);
this.ctrl.name.setValue(data.name);
this.ctrl.date_modify.setValue(data.date_modify);
});
}


Описание типа почтовое уведомления:


/**
* Почтовое уведомление
*
* @export
* @interface IPostTemplate
*/
export interface IPostTemplate {
/** Id */
id?: string;
/** Код почтового уведомления */
code: string;
/** Название почтового уведомления */
name: string;
/** Дата изменения */
date_modify?: string;
/** Флаг активен или нет */
active?: string;
/** Флаг текст или нет */
is_text?: string;
/** Титул */
title?: string;
/** Контент */
content?: string;
}

Класс почтового уведомления:

export class PostTemplate implements IPostTemplate {
id?: string;
code: string;
name: string;
active?: string;
is_text?: string;
date_modify: string;
title?: string;
content?: string;

constructor(
data: IPostTemplate
) {
this.id = data.id || undefined;
this.code = data.code || '';
this.name = data.name || '';
this.date_modify = data.date_modify || '';
this.active = data.active || '';
this.is_text = data.is_text || '';
}
}

destus
25.11.2019, 19:53
Думаю первый вариант - это ок. Кстати, можно вызвать componentForm.setValue(data), вместо того чтобы устанивливать значения для каждого из контролов отдельно.

shtangen
28.11.2019, 12:47
Спасибо, за хорошее замечание, код допилил. :thanks: