ControlValueAccessor를 사용하여 Angular에서 사용자 지정 양식 컨트롤을 만드는 방법
소개
Angular에서 양식을 만들 때 표준 텍스트 입력, 선택 또는 확인란이 아닌 입력을 원할 때가 있습니다. ControlValueAccessor
인터페이스를 구현하고 구성 요소를 NG_VALUE_ACCESSOR
로 등록하면 사용자 지정 양식 컨트롤을 기본 입력인 것처럼 템플릿 기반 또는 반응형 양식에 원활하게 통합할 수 있습니다. !

이 문서에서는 기본 별 등급 입력 구성 요소를 ControlValueAccessor
로 변환합니다.
전제 조건
이 자습서를 완료하려면 다음이 필요합니다.
- Node.js를 로컬에 설치했습니다. Node.js를 설치하고 로컬 개발 환경을 만드는 방법에 따라 수행할 수 있습니다.
- Angular 구성 요소 사용에 어느 정도 익숙하면 도움이 될 수 있습니다.
이 튜토리얼은 Node v16.4.2, npm
v7.18.1, angular
v12.1.1에서 확인되었습니다.
1단계 - 프로젝트 설정
먼저 새 RatingInputComponent
를 만듭니다.
이것은 @angular/cli
로 수행할 수 있습니다.
- ng generate component rating-input --inline-template --inline-style --skip-tests --flat --prefix
이렇게 하면 앱 declarations
에 새 구성 요소가 추가되고 rating-input.component.ts
파일이 생성됩니다.
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'rating-input',
template: `
<p>
rating-input works!
</p>
`,
styles: [
]
})
export class RatingInputComponent implements OnInit {
constructor() { }
ngOnInit(): void {
}
}
템플릿, 스타일 및 논리를 추가합니다.
import { Component } from '@angular/core';
@Component({
selector: 'rating-input',
template: `
<span
<^>*ngFor="let starred of stars; let i = index"
(click)="rate(i + (starred ? (value > i + 1 ? 1 : 0) : 1))"<^>
>
<ng-container *ngIf="starred; else noStar">⭐</ng-container>
<ng-template #noStar>·</ng-template>
</span>
`,
styles: [`
span {
display: inline-block;
width: 25px;
line-height: 25px;
text-align: center;
cursor: pointer;
}
`]
})
export class RatingInputComponent {
stars: boolean[] = Array(5).fill(false);
get value(): number {
return this.stars.reduce((total, starred) => {
return total + (starred ? 1 : 0);
}, 0);
}
rate(rating: number) {
this.stars = this.stars.map((_, i) => rating > i);
}
}
구성 요소의 값
(0
에서 5
)을 가져오고 rate
를 호출하여 구성 요소의 값을 설정할 수 있습니다. 코드> 기능을 사용하거나 원하는 별의 수를 클릭하십시오.
응용 프로그램에 구성 요소를 추가할 수 있습니다.
<rating-input></rating-input>
그리고 애플리케이션을 실행합니다.
- ng serve
그리고 웹 브라우저에서 상호 작용합니다.
이것은 훌륭하지만 이 입력을 양식에 추가하고 모든 것이 아직 작동하기를 기대할 수는 없습니다. ControlValueAccessor
로 만들어야 합니다.
2단계 - 사용자 지정 양식 컨트롤 만들기
RatingInputComponent
가 기본 입력(따라서 진정한 사용자 지정 양식 컨트롤)인 것처럼 동작하도록 하려면 Angular에 몇 가지 작업을 수행하도록 알려야 합니다.
- 입력에 값 쓰기 -
writeValue
- 입력 값이 변경될 때 Angular에 알리는 함수 등록 -
registerOnChange
- 입력이 터치되었을 때 Angular에 알리는 함수 등록 -
registerOnTouched
- 입력 비활성화 -
setDisabledState
이 네 가지가 ControlValueAccessor
인터페이스, 양식 컨트롤과 기본 요소 또는 사용자 지정 입력 구성 요소 사이의 브리지를 구성합니다. 구성 요소가 해당 인터페이스를 구현하면 사용할 수 있도록 NG_VALUE_ACCESSOR
로 제공하여 Angular에 알려야 합니다.
코드 편집기에서 rating-input.component.ts
를 다시 방문하여 다음과 같이 변경합니다.
import { Component, forwardRef, HostBinding, Input } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
@Component({
selector: 'rating-input',
template: `
<span
*ngFor="let starred of stars; let i = index"
(click)="onTouched(); rate(i + (starred ? (value > i + 1 ? 1 : 0) : 1))"
>
<ng-container *ngIf="starred; else noStar">⭐</ng-container>
<ng-template #noStar>·</ng-template>
</span>
`,
styles: [`
span {
display: inline-block;
width: 25px;
line-height: 25px;
text-align: center;
cursor: pointer;
}
`],
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => RatingInputComponent),
multi: true
}
]
})
export class RatingInputComponent implements ControlValueAccessor {
stars: boolean[] = Array(5).fill(false);
// Allow the input to be disabled, and when it is make it somewhat transparent.
@Input() disabled = false;
@HostBinding('style.opacity')
get opacity() {
return this.disabled ? 0.25 : 1;
}
// Function to call when the rating changes.
onChange = (rating: number) => {};
// Function to call when the input is touched (when a star is clicked).
onTouched = () => {};
get value(): number {
return this.stars.reduce((total, starred) => {
return total + (starred ? 1 : 0);
}, 0);
}
rate(rating: number) {
if (!this.disabled) {
this.writeValue(rating);
}
}
// Allows Angular to update the model (rating).
// Update the model and changes needed for the view here.
writeValue(rating: number): void {
this.stars = this.stars.map((_, i) => rating > i);
this.onChange(this.value);
}
// Allows Angular to register a function to call when the model (rating) changes.
// Save the function as a property to call later here.
registerOnChange(fn: (rating: number) => void): void {
this.onChange = fn;
}
// Allows Angular to register a function to call when the input has been touched.
// Save the function as a property to call later here.
registerOnTouched(fn: () => void): void {
this.onTouched = fn;
}
// Allows Angular to disable the input.
setDisabledState(isDisabled: boolean): void {
this.disabled = isDisabled;
}
}
이 코드는 입력을 비활성화할 수 있도록 하며 비활성화되면 어느 정도 투명하게 만듭니다.
애플리케이션을 실행합니다.
- ng serve
그리고 웹 브라우저에서 상호 작용합니다.
입력 컨트롤을 비활성화할 수도 있습니다.
<rating-input [disabled]="true"></rating-input>
이제 RatingInputComponent
가 사용자 지정 양식 구성 요소라고 말할 수 있습니다! 템플릿 기반 또는 반응형 형식에서 다른 기본 입력(Angular는 ControlValueAccessors
을 제공합니다!)과 동일하게 작동합니다.
결론
이 문서에서는 기본 별 등급 입력 구성 요소를 ControlValueAccessor
로 변환했습니다.
이제 다음을 알 수 있습니다.
ngModel
은 "작동\합니다.- 맞춤형 유효성 검사를 추가할 수 있습니다.
- 제어 상태 및 유효성은
ng-dirty
및ng-touched
클래스와 같은ngModel
에서 사용할 수 있습니다.
Angular에 대해 자세히 알아보려면 연습 및 프로그래밍 프로젝트에 대한 Angular 주제 페이지를 확인하세요.