I have Multiple Sections Each Containing Subsections and inside I have Questions that I need to validate, The Thing is:
I have a save button for each section.
Edit: I Don't know how many Sections I will have from Api and how many Subsections or Questions its all dynamic
how do I make: FormGroup for each Subsection. and inside Subsections I have array of questions(fields) that I need to have FormControls for. what I want to achieve is: SectionForm1.isValid save();, SectionForm2.isValid save()...
I've tried doing this. but it adds formControl for all fields. Demo
CodePudding user response:
If you have to make components inside Forms you should create custom FormControls (you can read this article)
If you want a snippet to check if every control is valid you can do as follows:
checkValidity(): void {
const findInvalidControls = () => {
const invalid = [];
const controls = ...this.form.controls;
for (const name in controls) {
if ((controls as any)[name]?.invalid) {
invalid.push(name);
}
}
return invalid;
};
const invalid = findInvalidControls();
// Do something if "invalid.length" is > 0
}
In order for this to work, you have to make sure that when you create a FormControl, you set some validators, for example:
In your component.ts:
private control = new FormControl('') // Initialize the control with a value. Can be a value of '' if it's a string
private control = new FormControl('', [Validators.required]) // Set the validators in your control
private control = new FormControl<string>('', [Validators.required]) // Take advantages of typed FormControls
CodePudding user response:
Here is a simplified version of how I handled large forms with different sections and logic in a large project. Not sure, if it fits to your problem.
Create a parent component and a Subsection Component for each subsection including a own formgroup, save logic, etc.
<!-- Parent Component HTML -->
<subsection1-form #subsection1Form></subsection1-form>
<subsection2-form #subsection2Form></subsection2-form>
// Parent Component TS
@ViewChild('subsection1Form') subsection1Form: Subsection1FormComponent;
@ViewChild('subsection2Form') subsection2Form: Subsection2FormComponent;
/** Call this method to save all subsections */
save() {
this.subsection1Form.form.markAllAsTouched();
this.subsection2Form.form.markAllAsTouched();
if (this.subsection1Form.valid && this.subsection2Form.valid ) {
forkJoin([
this.subsection1Form.submit(),
this.subsection2Form.submit()
]).subscribe(/* ... */);
}
}
I also created a simple interface for SubsectionForms and let the subsection components implement it.
export interface SubsectionForm {
/** Make a request and return the response if it is successful. On errors return
Overservable<never>. */
submit(): Observable<any>;
}
}
And the SubsectionComponent would look like this:
@Component({
selector: 'subsection1-form',
templateUrl: './subsection1-form.component.html',
styleUrls: ['./subsection1-form.component.scss']
})
export class Subsection1FormComponent implements OnInit, SubsectionForm {
@ViewChild('form') form: NgForm;
submit(): Observable<any> {
// Do something
}
}
This way, the subsections business logic is nicely encapsuled.
I think this is also pretty flexible:
- Subsections can also returns anything else. Doesn't need to return an Observable.
- You can add more validation either in subsections directly or in parent component if it is "cross-subsection" logic
For dynamic Forms you can replace the subsection components with a dynamic FormGroup-array.
// Parent Component TS
subsections: FormGroup[];
initializeSubsections(): void {
// However, create/initialize/update the different forms dynamically
}
/** Call this method to save all subsections */
save() {
this.subsections.forEach((form: FormGroup) => form.markAllAsTouched());
if (this.subsections.every(({ valid }: FormGroup) => valid)) {
// Do something with your subsections
}
}
Maybe you can combine it, if you can create a generic subsection component.
<!-- in Parent Component HTML -->
<!-- you can also create a more complex array with additional input parameters, not only the formGroup -->
<subsection-component *ngFor="let form in subsections; index as i" [form]="form" (submit)="submit(i)"></subsection-component>
// Added in Parent Component TS
submit(index: number) {
if (this.subsections[i].valid) {
// Do something with subsection i
}
}
CodePudding user response:
As i see you are using child component .To fix this issue .Firstly you have to use ControlvalueAccessor in your child component. click here . Here is eg. how to use this click here