ในความเป็นจริงมีสองสิ่งที่ต้องดำเนินการ:
- ส่วนประกอบที่ให้ตรรกะของส่วนประกอบฟอร์มของคุณ ไม่จำเป็นต้องมีการป้อนข้อมูลเนื่องจากจะมีให้ด้วย
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") สำหรับรายละเอียดเพิ่มเติม: