त्रुटि का मतलब है, कि कोणीय को पता नहीं है कि जब आप एक formControl
पर डालते हैं तो क्या करना है div
। इसे ठीक करने के लिए, आपके पास दो विकल्प हैं।
- आप
formControlName
एक तत्व पर डालते हैं , जो बॉक्स से बाहर कोणीय द्वारा समर्थित है। उन हैं: input
, textarea
औरselect
।
- आप
ControlValueAccessor
इंटरफ़ेस लागू करें। ऐसा करके, आप कोणीय "अपने नियंत्रण के मूल्य का उपयोग कैसे करें" (इसलिए नाम) बता रहे हैं। या सरल शब्दों में: क्या करें, जब आप 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
इंटरफ़ेस लागू किया था
- बी) सुनिश्चित करता है कि आप
ControlValueAccessor
इंटरफ़ेस लागू कर रहे हैं
- ग) यह शायद सबसे भ्रमित करने वाला हिस्सा है। मूल रूप से आप क्या कर रहे हैं, आप अपनी कक्षा की संपत्तियों / विधियों को ओवरराइड करने के लिए कोणीय साधन देते हैं
onChange
औरonTouch
रनटाइम के दौरान इसका स्वयं का कार्यान्वयन होता है, जैसे कि आप तब उन कार्यों को कॉल कर सकते हैं। इसलिए इस बिंदु को समझना महत्वपूर्ण है: आपको onChange और onTouch को स्वयं लागू करने की आवश्यकता नहीं है (प्रारंभिक खाली कार्यान्वयन के अलावा)। केवल एक चीज जो आपके (c) के साथ कर रही है, वह यह है कि कोणीय संलग्न करना आपकी कक्षा के लिए स्वयं के कार्य हैं। क्यों? तो तुम तो कर सकते हैं फोनonChange
औरonTouch
उचित समय पर कोणीय द्वारा प्रदान तरीकों। हम देखेंगे कि यह नीचे कैसे काम करता है।
- d) हम यह भी देखेंगे कि
writeValue
जब हम इसे लागू करते हैं तो यह विधि अगले भाग में कैसे काम करती है। मैंने इसे यहां रखा है, इसलिए सभी आवश्यक गुण ControlValueAccessor
लागू किए गए हैं और आपका कोड अभी भी संकलित है।
राइटवॉल लागू करें
क्या 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">
आप इसे सीधे इनपुट तत्व पर भी लिख सकते हैं जैसा कि कोणीय डॉक्स में वर्णित है।
अब आप संभाल चुके हैं कि आपके घटक के अंदर क्या होता है जब कुछ बाहर बदलता है। अब दूसरी दिशा को देखते हैं। जब आप अपने घटक के अंदर कुछ परिवर्तन करते हैं तो आप बाहरी दुनिया को कैसे सूचित करते हैं?
OnChange बुला रहा है
अगला कदम मूल घटक को आपके अंदर के परिवर्तनों के बारे में सूचित करना है CustomInputComponent
। यह वह जगह है जहाँ ऊपर से (सी) onChange
और onTouch
कार्य चलन में आते हैं। उन कार्यों को कॉल करके आप अपने घटक के अंदर परिवर्तनों के बारे में बाहर की सूचना दे सकते हैं। मूल्य के परिवर्तनों को बाहर तक प्रचारित करने के लिए, आपको तर्क के रूप में नए मूल्य के साथ onChange को कॉल करने की आवश्यकता है । उदाहरण के लिए, यदि उपयोगकर्ता input
आपके कस्टम घटक में फ़ील्ड में कुछ टाइप करता है , तो आप onChange
अद्यतन मूल्य के साथ कॉल करते हैं:
<input type="text"
[ngModel]="input"
(ngModelChange)="onChange($event)">
यदि आप कार्यान्वयन (सी) को फिर से ऊपर से देखते हैं, तो आप देखेंगे कि क्या हो रहा है: कोणीय बाध्य इसका स्वयं का कार्यान्वयन है onChange
वर्ग की संपत्ति के । यह कार्यान्वयन एक तर्क की अपेक्षा करता है, जो अद्यतन नियंत्रण मूल्य है। अब आप जो कर रहे हैं, आप उस विधि को कॉल कर रहे हैं और इस प्रकार परिवर्तन के बारे में कोणीय को बता सकते हैं। कोणीय अब आगे बढ़ेगा और बाहर के रूप में मूल्य बदल देगा। इस सब में यह महत्वपूर्ण हिस्सा है। आपने एंगुलर को बताया कि कब उसे फॉर्म कंट्रोल और किस वैल्यू पर कॉल करके अपडेट करना चाहिएonChange
। आपने इसे "नियंत्रण मूल्य तक पहुंचने" का साधन दिया है।
वैसे: नाम onChange
मेरे द्वारा चुना गया है। आप यहां कुछ भी चुन सकते हैं, उदाहरण के लिए propagateChange
या समान। हालाँकि आप इसे नाम देते हैं, यह वही फ़ंक्शन होगा जो एक तर्क लेता है, जो कि कोणीय द्वारा प्रदान किया गया है और जो आपके वर्ग के लिए बाध्य हैregisterOnChange
रनटाइम के दौरान विधि है।
फोन पर कॉलिंग
चूंकि फ़ॉर्म नियंत्रण "छुआ जा सकता है", इसलिए आपको अपने कस्टम फॉर्म नियंत्रण को छूने पर समझने के लिए कोणीय को भी साधन देना चाहिए। आप इसे कर सकते हैं, आपने इसे अनुमान लगाया, onTouch
फ़ंक्शन को कॉल करके । तो हमारे उदाहरण के लिए, यदि आप यह जानना चाहते हैं कि कोणीय रूप से आउट-ऑफ-द-बॉक्स नियंत्रण के लिए यह कैसे किया जाता है, तो आपको onTouch
इनपुट फ़ील्ड के धुंधला होने पर कॉल करना चाहिए :
<input type="text"
[(ngModel)]="input"
(ngModelChange)="onChange($event)"
(blur)="onTouch()">
फिर से, onTouch
मेरे द्वारा चुना गया एक नाम है, लेकिन यह वास्तविक कार्य क्या है यह कोणीय द्वारा प्रदान किया गया है और यह शून्य तर्क लेता है। जो समझ में आता है, क्योंकि आप केवल कोणीय को बता रहे हैं, कि प्रपत्र नियंत्रण को छू लिया गया है।
यह सब एक साथ डालें
तो जब यह सब एक साथ आता है तो यह कैसा दिखता है? इसे ऐसा दिखना चाहिए:
// 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
सूत्रों का कहना है