실제로 구현해야 할 두 가지가 있습니다.
- 양식 구성 요소의 논리를 제공하는 구성 요소입니다.
ngModel
자체적 으로 제공되므로 입력이 필요하지 않습니다.
ControlValueAccessor
이 구성 요소와 ngModel
/ 사이의 브리지를 구현할 사용자 지정ngControl
샘플을 봅시다. 회사의 태그 목록을 관리하는 구성 요소를 구현하고 싶습니다. 구성 요소는 태그를 추가 및 제거 할 수 있습니다. 태그 목록이 비어 있지 않은지 확인하기 위해 유효성 검사를 추가하고 싶습니다. 아래에 설명 된대로 구성 요소에서 정의합니다.
(...)
import {TagsComponent} from './app.tags.ngform';
import {TagsValueAccessor} from './app.tags.ngform.accessor';
function notEmpty(control) {
if(control.value == null || control.value.length===0) {
return {
notEmpty: true
}
}
return null;
}
@Component({
selector: 'company-details',
directives: [ FormFieldComponent, TagsComponent, TagsValueAccessor ],
template: `
<form [ngFormModel]="companyForm">
Name: <input [(ngModel)]="company.name"
[ngFormControl]="companyForm.controls.name"/>
Tags: <tags [(ngModel)]="company.tags"
[ngFormControl]="companyForm.controls.tags"></tags>
</form>
`
})
export class DetailsComponent implements OnInit {
constructor(_builder:FormBuilder) {
this.company = new Company('companyid',
'some name', [ 'tag1', 'tag2' ]);
this.companyForm = _builder.group({
name: ['', Validators.required],
tags: ['', notEmpty]
});
}
}
TagsComponent
구성 요소를 추가하고 요소 제거하는 로직 정의 tags
목록을.
@Component({
selector: 'tags',
template: `
<div *ngIf="tags">
<span *ngFor="#tag of tags" style="font-size:14px"
class="label label-default" (click)="removeTag(tag)">
{{label}} <span class="glyphicon glyphicon-remove"
aria- hidden="true"></span>
</span>
<span> | </span>
<span style="display:inline-block;">
<input [(ngModel)]="tagToAdd"
style="width: 50px; font-size: 14px;" class="custom"/>
<em class="glyphicon glyphicon-ok" aria-hidden="true"
(click)="addTag(tagToAdd)"></em>
</span>
</div>
`
})
export class TagsComponent {
@Output()
tagsChange: EventEmitter;
constructor() {
this.tagsChange = new EventEmitter();
}
setValue(value) {
this.tags = value;
}
removeLabel(tag:string) {
var index = this.tags.indexOf(tag, 0);
if (index != undefined) {
this.tags.splice(index, 1);
this.tagsChange.emit(this.tags);
}
}
addLabel(label:string) {
this.tags.push(this.tagToAdd);
this.tagsChange.emit(this.tags);
this.tagToAdd = '';
}
}
보시다시피이 구성 요소에는 입력이 없지만 setValue
하나입니다 (여기서 이름은 중요하지 않음). 나중에 ngModel
에서 구성 요소로 값을 제공하는 데 사용합니다 . 이 구성 요소는 구성 요소 (태그 목록)의 상태가 업데이트 될 때 알리는 이벤트를 정의합니다.
이제이 구성 요소와 ngModel
/ 간의 링크를 구현해 보겠습니다 ngControl
. 이는 ControlValueAccessor
인터페이스 를 구현하는 지시문에 해당합니다 . NG_VALUE_ACCESSOR
토큰 에 대해이 값 접근 자에 대해 공급자를 정의해야합니다 ( forwardRef
지시문이 이후에 정의되므로 사용하는 것을 잊지 마십시오 ).
지시문은 tagsChange
호스트 의 이벤트에 이벤트 리스너를 첨부합니다 (예 : 지시문이 첨부 된 구성 요소, 즉 TagsComponent
). onChange
이벤트가 발생할 때 메서드가 호출됩니다. 이 방법은 Angular2에서 등록한 방법에 해당합니다. 이렇게하면 관련 양식 컨트롤에 따라 변경 및 업데이트를 인식하게됩니다.
에 writeValue
바인딩 된 값 ngForm
이 업데이트 되면이 호출 됩니다. 첨부 된 컴포넌트 (예 : TagsComponent)를 삽입 한 후이 값을 전달하기 위해 호출 할 수 있습니다 (이전 setValue
메서드 참조 ).
CUSTOM_VALUE_ACCESSOR
지시문의 바인딩에 를 제공하는 것을 잊지 마십시오 .
다음은 사용자 정의의 전체 코드입니다 ControlValueAccessor
.
import {TagsComponent} from './app.tags.ngform';
const CUSTOM_VALUE_ACCESSOR = CONST_EXPR(new Provider(
NG_VALUE_ACCESSOR, {useExisting: forwardRef(() => TagsValueAccessor), multi: true}));
@Directive({
selector: 'tags',
host: {'(tagsChange)': 'onChange($event)'},
providers: [CUSTOM_VALUE_ACCESSOR]
})
export class TagsValueAccessor implements ControlValueAccessor {
onChange = (_) => {};
onTouched = () => {};
constructor(private host: TagsComponent) { }
writeValue(value: any): void {
this.host.setValue(value);
}
registerOnChange(fn: (_: any) => void): void { this.onChange = fn; }
registerOnTouched(fn: () => void): void { this.onTouched = fn; }
}
이렇게 tags
하면 회사 전체를 제거 valid
하면 companyForm.controls.tags
컨트롤 의 속성 이 false
자동으로 나타납니다.
자세한 내용은이 문서 ( "NgModel 호환 구성 요소"섹션)를 참조하십시오.