टी एल; डॉ
- मैं चेकबॉक्स की सूची को पॉप्युलेट करने के लिए फॉर्मग्रुप का उपयोग करना पसंद करता हूं
- कम से कम एक चेकबॉक्स का चयन करने के लिए कस्टम सत्यापनकर्ता लिखें
- वर्किंग उदाहरण https://stackblitz.com/edit/angular-validate-at-least-one-checkbox-was-selected
इसने भी मुझे कभी-कभी मारा, इसलिए मैंने फॉर्मअरे और फॉर्मग्रुप दोनों तरीकों की कोशिश की।
ज्यादातर समय, चेकबॉक्स की सूची सर्वर पर पॉपुलेटेड थी और मैंने इसे एपीआई के माध्यम से प्राप्त किया। लेकिन कभी-कभी आपके पास अपने पूर्वनिर्धारित मूल्य के साथ चेकबॉक्स का एक स्थिर सेट होगा। प्रत्येक उपयोग के मामले में, संबंधित फॉर्मअरे या फॉर्मग्रुप का उपयोग किया जाएगा।
मूल रूप से FormArray
इसका एक प्रकार है FormGroup
। मुख्य अंतर यह है कि इसका डेटा एक सरणी के रूप में क्रमबद्ध हो जाता है (फॉर्मग्रुप के मामले में ऑब्जेक्ट के रूप में क्रमबद्ध होने के विपरीत)। यह विशेष रूप से उपयोगी हो सकता है जब आप नहीं जानते कि समूह के भीतर गतिशील रूपों की तरह कितने नियंत्रण मौजूद होंगे।
सादगी के लिए, आप के साथ एक सरल उत्पाद बनाने की कल्पना करो
- एक आवश्यक उत्पाद का नाम टेक्स्टबॉक्स।
- चयन करने के लिए श्रेणी की एक सूची, कम से कम एक को जांचना आवश्यक है। मान लें कि सूची सर्वर से पुनर्प्राप्त की जाएगी।
सबसे पहले, मैंने केवल उत्पाद नाम formControl के साथ एक फॉर्म सेट किया। यह एक आवश्यक क्षेत्र है।
this.form = this.formBuilder.group({
name: ["", Validators.required]
});
चूंकि श्रेणी गतिशील रूप से प्रदान कर रही है, इसलिए मुझे डेटा तैयार होने के बाद इन आंकड़ों को फॉर्म में जोड़ना होगा।
this.getCategories().subscribe(categories => {
this.form.addControl("categoriesFormArr", this.buildCategoryFormArr(categories));
this.form.addControl("categoriesFormGroup", this.buildCategoryFormGroup(categories));
})
श्रेणी सूची बनाने के लिए दो दृष्टिकोण हैं।
1. रूप
buildCategoryFormArr(categories: ProductCategory[], selectedCategoryIds: string[] = []): FormArray {
const controlArr = categories.map(category => {
let isSelected = selectedCategoryIds.some(id => id === category.id);
return this.formBuilder.control(isSelected);
})
return this.formBuilder.array(controlArr, atLeastOneCheckboxCheckedValidator())
}
<div *ngFor="let control of categoriesFormArr?.controls; let i = index" class="checkbox">
<label><input type="checkbox" [formControl]="control" />
{{ categories[i]?.title }}
</label>
</div>
यह buildCategoryFormGroup
मुझे एक फॉर्मअरे वापस कर देगा। यह एक तर्क के रूप में चयनित मूल्य की एक सूची भी लेता है इसलिए यदि आप संपादन डेटा के लिए फ़ॉर्म का पुन: उपयोग करना चाहते हैं, तो यह उपयोगी हो सकता है। एक नया उत्पाद बनाने के उद्देश्य के लिए, यह अभी तक लागू नहीं है।
यह ध्यान दिया जाता है कि जब आप formArray मानों को एक्सेस करने का प्रयास करते हैं। ऐसा लगेगा [false, true, true]
। चयनित आईडी की एक सूची प्राप्त करने के लिए, इसे सूची से जांचने के लिए थोड़ा और काम करने की आवश्यकता थी लेकिन सरणी सूचकांक पर आधारित। मुझे अच्छा नहीं लगता लेकिन यह काम करता है।
get categoriesFormArraySelectedIds(): string[] {
return this.categories
.filter((cat, catIdx) => this.categoriesFormArr.controls.some((control, controlIdx) => catIdx === controlIdx && control.value))
.map(cat => cat.id);
}
इसलिए मैं FormGroup
उस मामले के लिए उपयोग कर रहा हूं
2. समूह
फ़ॉर्मग्रुप का भिन्न रूप वह है जो प्रपत्र डेटा को ऑब्जेक्ट के रूप में संग्रहित करेगा, जिसके लिए एक कुंजी और फ़ॉर्म नियंत्रण की आवश्यकता होती है। इसलिए यह महत्वपूर्ण है कि श्रेणीआईड के रूप में कुंजी सेट करें और फिर हम इसे बाद में पुनः प्राप्त कर सकते हैं।
buildCategoryFormGroup(categories: ProductCategory[], selectedCategoryIds: string[] = []): FormGroup {
let group = this.formBuilder.group({}, {
validators: atLeastOneCheckboxCheckedValidator()
});
categories.forEach(category => {
let isSelected = selectedCategoryIds.some(id => id === category.id);
group.addControl(category.id, this.formBuilder.control(isSelected));
})
return group;
}
<div *ngFor="let item of categories; let i = index" class="checkbox">
<label><input type="checkbox" [formControl]="categoriesFormGroup?.controls[item.id]" /> {{ categories[i]?.title }}
</label>
</div>
प्रपत्र समूह का मान इस तरह दिखेगा:
{
"category1": false,
"category2": true,
"category3": true,
}
लेकिन अक्सर हम केवल श्रेणी सूची के रूप में प्राप्त करना चाहते हैं ["category2", "category3"]
। मुझे इन आंकड़ों को लेने के लिए भी लिखना होगा। मुझे इस दृष्टिकोण को फॉर्मअरे की तुलना में बेहतर लगता है, क्योंकि मैं वास्तव में फॉर्म से ही मूल्य ले सकता था।
get categoriesFormGroupSelectedIds(): string[] {
let ids: string[] = [];
for (var key in this.categoriesFormGroup.controls) {
if (this.categoriesFormGroup.controls[key].value) {
ids.push(key);
}
else {
ids = ids.filter(id => id !== key);
}
}
return ids;
}
3. कम से कम एक चेकबॉक्स की जांच करने के लिए कस्टम सत्यापनकर्ता का चयन किया गया था
मैंने सत्यापनकर्ता को कम से कम X चेकबॉक्स चयनित करने के लिए बनाया था, डिफ़ॉल्ट रूप से यह केवल एक चेकबॉक्स के खिलाफ जांच करेगा।
export function atLeastOneCheckboxCheckedValidator(minRequired = 1): ValidatorFn {
return function validate(formGroup: FormGroup) {
let checked = 0;
Object.keys(formGroup.controls).forEach(key => {
const control = formGroup.controls[key];
if (control.value === true) {
checked++;
}
});
if (checked < minRequired) {
return {
requireCheckboxToBeChecked: true,
};
}
return null;
};
}