반응형
angualr Reactive Forms 과 ngModel 함께 사용
angular는 ngmodel 이라는 양방향 바인딩 처리가 최대 장점이고 더불어 Reactive Forms 을 이용해서
ngmodel의 양방향 바인딩 데이터를 실시간으로 원하는 곳으로 전달하는 구조를 가지고 있었는데,버전 6번부터는 ngmodel과 Reactive Forms FormControl을 함께 쓰는것을 권장하지 않고 있습니다.참으로 유용한 기능이라고 생각했는데 둘을 혼용해서 사용할때 시점 차이가 종종 발생해서 데이터의 흐름과 코드 구성이 혼란스러워 져서 예상치 못한 동작이 발생할수 있기 때문에 함께 쓰는것을 권장하지않습니다.하지만 값의 변경사항을 실시간으로 웹 서버에 전달하는 최선의 방법은 둘을 함께 사용하는 것입니다.그래서 아래와 같은 코드 구조를 사용해서 템플릿에서는 둘을 혼용하지 않고 사용하는 방법을 많이 사용합니다.
import { Component } from '@angular/core';
import { FormControl } from '@angular/forms';
@Component({
selector: 'app-example',
template: `
<input [(ngModel)]="ngModelValue" (ngModelChange)="updateFormControlValue()" />
`,
})
export class ExampleComponent {
formControl = new FormControl('');
ngModelValue: string = '';
updateFormControlValue() {
// FormControl 값을 업데이트하고 ngModel에 할당합니다.
this.formControl.setValue(this.ngModelValue);
}
}
하지만 ngmodel을 통해 입력 받아야 하는 항목이 많은 경우에는 매번 formcontrol을 변경하는 코드를 생성해줘야 합니다. 그래서 아래의 코드를 통해 일괄적으로 값을 전달할 수 있도록 구성했습니다.
import { OnInit, OnDestroy, Component } from '@angular/core';
import { FormGroup, FormControl, FormBuilder } from '@angular/forms';
import { distinctUntilChanged, debounceTime, takeUntil } from 'rxjs/operators';
import { ReplaySubject } from 'rxjs';
export class DataModel {
code: any;
qty: number;
title: string;
};
export interface ControlMapping {
form: any;
obj: any;
model: any;
formControlName: string;
};
@Component({
selector: 'app-example',
template: `
<input [(ngModel)]="data.code" />
<input [(ngModel)]="data.qty" />
<input [(ngModel)]="data.title" />
`,
})
export class ExampleComponent implements OnInit, OnDestroy {
private destroyed$: ReplaySubject<boolean> = new ReplaySubject(1);
public ExampleForm: FormGroup;
public data = new DataModel();
constructor(public fb: FormBuilder) {
this.ExampleForm = fb.group({
code: new FormControl(''),
qty: new FormControl(''),
title: new FormControl('')});
const controlMappings: ControlMapping[] = [
{ form: this.ExampleForm, obj: this.data, model: 'code', formControlName: 'code' },
{ form: this.ExampleForm, obj: this.data, model: 'qty', formControlName: 'qty' },
{ form: this.ExampleForm, obj: this.data, model: 'title', formControlName: 'title' }
];
controlMappings.forEach(mapping => {
this.FormControlChange(mapping.form, mapping.obj, mapping.model, mapping.formControlName);
});
}
public ChangeFormControl(form: FormGroup, obj: any, model: any, formControlName: string): void {
Object.defineProperty(obj, model, {
get: () => {
const value = form.get(formControlName)?.value;
return isNaN(value) ? value : parseFloat(value);
},
set: (newValue: any) => {
const convertedValue = isNaN(newValue) ? newValue : parseFloat(newValue);
form.get(formControlName)?.setValue(convertedValue, { emitEvent: true });
}
});
}
public ngOnInit(): void {
this.ExampleForm.valueChanges
.pipe(debounceTime(200), distinctUntilChanged(), takeUntil(this.destroyed$))
.subscribe((frm: any) => {
console.log(frm);
}, (err: any) => {
console.log(err);
});
}
public ngOnDestroy(): void {
this.destroyed$.next(true);
this.destroyed$.complete();
}
}
반응형
'개발 > front-end' 카테고리의 다른 글
angular 카카오맵 api 연동 (0) | 2024.07.05 |
---|---|
angular 비동기(async) 처리 (0) | 2024.07.05 |
angular 별도 라이브러리 없이 tree 기능 구현 (0) | 2023.04.01 |
angular 이미지 로딩 속도 개선 (0) | 2023.04.01 |
Angular의 ExpressionChangedAfterItHasBeenCheckedError (0) | 2023.04.01 |