ত্রুটির অর্থ হ'ল, কৌনিকটি জানে না যে আপনি যখন একটি 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
}
তাহলে স্বতন্ত্র অংশগুলি কী করছে?
- ক) রানঘরের সময় কৌনিকটি জানতে দেয় যে আপনি
ControlValueAccessorইন্টারফেসটি প্রয়োগ করেছেন
- খ) আপনি
ControlValueAccessorইন্টারফেস প্রয়োগ করছেন তা নিশ্চিত করে
- গ) এটি সম্ভবত সবচেয়ে বিভ্রান্তিকর অংশ। মূলত আপনি যা করছেন তা হ'ল, আপনি কৌনিককে আপনার শ্রেণীর বৈশিষ্ট্য / পদ্ধতিগুলি ওভারটাইম করার উপায় দিয়েছিলেন
onChangeএবং onTouchরানটাইমের সময় এটির নিজস্ব প্রয়োগ রয়েছে, যাতে আপনি সেই ফাংশনগুলিকে কল করতে পারেন। সুতরাং এই পয়েন্টটি বোঝার জন্য গুরুত্বপূর্ণ: আপনাকে onChange এবং অন টিচ নিজেকে প্রয়োগ করতে হবে না (প্রাথমিক শূন্য বাস্তবায়ন ব্যতীত) 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;
}
এবং এইচটিএমএল এ CustomInputComponent:
<input type="text"
[ngModel]="input">
কৌণিক ডক্সে বর্ণিত হিসাবে আপনি এটি সরাসরি ইনপুট উপাদানটিতেও লিখতে পারেন।
বাইরে যখন কিছু পরিবর্তিত হয় তখন আপনি নিজের উপাদানটির ভিতরে কী ঘটে তা পরিচালনা করেছেন। এখন অন্য দিকটি দেখুন। আপনার উপাদানটির অভ্যন্তরে কিছু পরিবর্তন হলে আপনি কীভাবে বাইরের বিশ্বকে জানান?
কল করে অন চেঞ্জ
পরবর্তী পদক্ষেপটি আপনার অভ্যন্তরের পরিবর্তনের বিষয়ে পিতামাতার উপাদানকে অবহিত করা CustomInputComponent। এই যেখানে onChangeএবং onTouch(গ) থেকে ফাংশন উপরে থেকে খেলার মধ্যে আসা। এই ফাংশনগুলিতে কল করে আপনি আপনার উপাদানগুলির অভ্যন্তরের পরিবর্তনগুলি সম্পর্কে বাইরেকে অবহিত করতে পারেন। বাইরের মানটির পরিবর্তনগুলি প্রচার করার জন্য, আপনাকে আর্গুমেন্ট হিসাবে নতুন মান দিয়ে অন চেঞ্জ করতে হবে । উদাহরণস্বরূপ, যদি ব্যবহারকারী 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
সোর্স