오류는 Angular가에를 입을 때 무엇을 해야할지 모른다는 것을 의미 formControl
합니다 div
. 이 문제를 해결하려면 두 가지 옵션이 있습니다.
formControlName
상자에 Angular가 지원하는 요소를 넣습니다 . 사람들은 다음과 같습니다 input
, textarea
그리고 select
.
ControlValueAccessor
인터페이스를 구현합니다 . 그렇게함으로써 Angular에게 "컨트롤 값에 접근하는 방법"(이름)을 알려줍니다. 또는 간단한 용어로 : formControlName
요소 를 넣을 때 자연스럽게 관련된 값이없는해야 할 일.
이제 ControlValueAccessor
인터페이스를 구현하는 것은 처음에는 다소 어려울 수 있습니다. 특히 이것에 대한 문서가 많지 않기 때문에 코드에 많은 상용구를 추가해야합니다. 따라서 몇 가지 간단한 단계를 통해이를 분석해 보겠습니다.
양식 컨트롤을 자체 구성 요소로 이동
를 구현하려면 ControlValueAccessor
새 구성 요소 (또는 지시문)를 작성해야합니다. 폼 컨트롤과 관련된 코드를 이동하십시오. 이와 같이 쉽게 재사용 할 수 있습니다. 구성 요소 내부에 이미 컨트롤이있는 것은 처음부터 ControlValueAccessor
인터페이스 를 구현해야하는 이유 일 수 있습니다. 그렇지 않으면 사용자 지정 구성 요소를 각도 형식과 함께 사용할 수 없기 때문입니다.
상용구를 코드에 추가
ControlValueAccessor
인터페이스 구현 은 매우 장황합니다. 여기에 함께 제공되는 상용구가 있습니다.
import {Component, OnInit, forwardRef} from '@angular/core';
import {ControlValueAccessor, FormControl, NG_VALUE_ACCESSOR} from '@angular/forms';
@Component({
selector: 'app-custom-input',
templateUrl: './custom-input.component.html',
styleUrls: ['./custom-input.component.scss'],
// a) copy paste this providers property (adjust the component name in the forward ref)
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => CustomInputComponent),
multi: true
}
]
})
// b) Add "implements ControlValueAccessor"
export class CustomInputComponent implements ControlValueAccessor {
// c) copy paste this code
onChange: any = () => {}
onTouch: any = () => {}
registerOnChange(fn: any): void {
this.onChange = fn;
}
registerOnTouched(fn: any): void {
this.onTouch = fn;
}
// d) copy paste this code
writeValue(input: string) {
// TODO
}
개별 부품은 무엇입니까?
- a) 런타임 중에
ControlValueAccessor
인터페이스 를 구현했음을 Angular에 알립니다.
- b)
ControlValueAccessor
인터페이스를 구현하고 있는지 확인하십시오
- c) 아마도 가장 혼란스러운 부분 일 것입니다. 기본적으로 수행중인 작업은 Angular에게 클래스 속성 / 메소드를 재정의하는 수단을 제공
onChange
하고 onTouch
런타임 동안 자체 구현으로 해당 함수를 호출 할 수 있도록하는 것입니다. 따라서이 점을 이해하는 것이 중요합니다 . 처음 빈 구현 이외의 onChange 및 onTouch를 직접 구현할 필요는 없습니다 . (c)와 함께하는 유일한 일은 Angular가 클래스에 자체 함수를 첨부하도록하는 것입니다. 왜? 당신은 할 수 있습니다 전화 을onChange
onTouch
적절한 시간에 Angular에서 제공 및 메소드 . 우리는 이것이 아래에서 어떻게 작동하는지 볼 것입니다.
- d) 우리는이
writeValue
메소드가 구현 될 때 다음 섹션에서 어떻게 작동 하는지 볼 것이다. 여기에 넣었으므로 필요한 모든 속성 ControlValueAccessor
이 구현되고 코드가 여전히 컴파일됩니다.
writeValue 구현
무엇 writeValue
않습니다,하는 폼 컨트롤이 외부에서 변경 될 때, 사용자 정의 컴포넌트 안에 뭔가를 할 . 예를 들어, 사용자 지정 양식 컨트롤 구성 요소의 이름을 지정 app-custom-input
하고 다음과 같이 부모 구성 요소에서 사용하는 경우 :
<form [formGroup]="form">
<app-custom-input formControlName="myFormControl"></app-custom-input>
</form>
그런 다음 writeValue
부모 구성 요소가 어떻게 든 값을 변경할 때마다 트리거 myFormControl
됩니다. 예를 들어 양식 초기화 중에 this.form = this.formBuilder.group({myFormControl: ""});
또는 양식 재설정 중에있을 수 있습니다 this.form.reset();
.
양식 컨트롤의 값이 외부에서 변경되는 경우 일반적으로 수행하려는 작업은 양식 컨트롤 값을 나타내는 로컬 변수에 쓰는 것입니다. 예를 들어, CustomInputComponent
텍스트 기반 양식 컨트롤을 중심으로 회전 하면 다음과 같이 보일 수 있습니다.
writeValue(input: string) {
this.input = input;
}
그리고 html에서 CustomInputComponent
:
<input type="text"
[ngModel]="input">
Angular 문서에 설명 된대로 입력 요소에 직접 쓸 수도 있습니다.
이제 외부에서 무언가가 변경 될 때 구성 요소 내부에서 발생하는 작업을 처리했습니다. 이제 다른 방향을 봅시다. 컴포넌트 내부에서 무언가가 변경 될 때 어떻게 외부 세계에 알리나요?
onChange 호출
다음 단계는의 내부 변경 사항을 상위 구성 요소에 알리는 것 CustomInputComponent
입니다. 여기 에서 위의 (c) 의 onChange
및 onTouch
기능이 작동합니다. 이러한 함수를 호출하면 구성 요소 내부의 변경 사항을 외부에 알릴 수 있습니다. 값의 변경 사항을 외부로 전파 하려면 인수로 새 값을 사용하여 onChange 를 호출 해야합니다 . 예를 들어, 사용자가 사용자 input
정의 컴포넌트 의 필드에 무언가 onChange
를 입력하면 업데이트 된 값으로 호출 합니다.
<input type="text"
[ngModel]="input"
(ngModelChange)="onChange($event)">
위에서 구현 (c)를 다시 확인하면 무슨 일이 일어나고 있는지 알 수 있습니다 : Angular는 onChange
클래스 속성 에 대한 자체 구현 입니다. 이 구현에는 업데이트 된 제어 값인 하나의 인수가 필요합니다. 지금하고있는 일은 해당 메소드를 호출하여 Angular에 변경 사항을 알리는 것입니다. 이제 Angular가 외부의 양식 값을 변경합니다. 이것이이 모든 것의 핵심 부분입니다. Angular에 폼 컨트롤을 업데이트해야 할 때와를 호출하여 어떤 값으로 업데이트해야하는지 알려주었습니다onChange
. "제어 값에 액세스"하는 수단을 제공했습니다.
그건 그렇고 : 이름 onChange
은 나에 의해 선택됩니다. 예를 들어 propagateChange
또는 이와 유사한 것을 여기에서 선택할 수 있습니다 . 그러나 이름을 지정하면 Angular에서 제공하는 하나의 인수를 취하는 동일한 함수가됩니다.registerOnChange
런타임 동안 메소드에 됩니다.
onTouch 호출
폼 컨트롤을 "만질"수 있으므로 Angular는 사용자 지정 폼 컨트롤을 터치 할 때 이해할 수있는 수단을 제공해야합니다. onTouch
함수 를 호출하여 짐작할 수 있습니다 . 따라서 여기 예제에서, 즉시 사용 가능한 양식 컨트롤에 대해 Angular가 수행하는 방식을 준수 onTouch
하려면 입력 필드가 흐리게 표시 될 때 호출해야합니다 .
<input type="text"
[(ngModel)]="input"
(ngModelChange)="onChange($event)"
(blur)="onTouch()">
다시, onTouch
내가 선택한 이름이지만 실제 기능은 Angular에서 제공하며 인수가 없습니다. Angular에 알리기 때문에 양식 컨트롤이 터치되었음을 의미합니다.
함께 모아서
그래서 그것이 모두 함께 올 때 어떻게 보입니까? 다음과 같아야합니다.
// custom-input.component.ts
import {Component, OnInit, forwardRef} from '@angular/core';
import {ControlValueAccessor, FormControl, NG_VALUE_ACCESSOR} from '@angular/forms';
@Component({
selector: 'app-custom-input',
templateUrl: './custom-input.component.html',
styleUrls: ['./custom-input.component.scss'],
// Step 1: copy paste this providers property
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => CustomInputComponent),
multi: true
}
]
})
// Step 2: Add "implements ControlValueAccessor"
export class CustomInputComponent implements ControlValueAccessor {
// Step 3: Copy paste this stuff here
onChange: any = () => {}
onTouch: any = () => {}
registerOnChange(fn: any): void {
this.onChange = fn;
}
registerOnTouched(fn: any): void {
this.onTouch = fn;
}
// Step 4: Define what should happen in this component, if something changes outside
input: string;
writeValue(input: string) {
this.input = input;
}
// Step 5: Handle what should happen on the outside, if something changes on the inside
// in this simple case, we've handled all of that in the .html
// a) we've bound to the local variable with ngModel
// b) we emit to the ouside by calling onChange on ngModelChange
}
// custom-input.component.html
<input type="text"
[(ngModel)]="input"
(ngModelChange)="onChange($event)"
(blur)="onTouch()">
// parent.component.html
<app-custom-input [formControl]="inputTwo"></app-custom-input>
// OR
<form [formGroup]="form" >
<app-custom-input formControlName="myFormControl"></app-custom-input>
</form>
더 많은 예
중첩 양식
컨트롤 값 접근자는 중첩 된 양식 그룹에 적합한 도구가 아닙니다. 중첩 된 양식 그룹의 경우 간단히 @Input() subform
대신 사용할 수 있습니다 . 제어 값 액세서는 래퍼가 controls
아닌 랩을 의미합니다 groups
. 다음 예제는 중첩 양식에 입력을 사용하는 방법을 참조하십시오. https://stackblitz.com/edit/angular-nested-forms-input-2
출처