DEV Community

Ben
Ben

Posted on

Complex and Dynamic Form Design in Angular (Part 1 - Form Group)

Introduction

In Modern Web Application, a from could be very very very complicated. It would require a fancy layout, dynamic, validated, functional and also performance.

All make the Web Application Development difficult and cost so much resource. All the developed framework tried to make it easier but still very very very difficult.

Here, I would like to share some approaches to handle it in Angular.

  • Form Group as Parameter (FormGroup Approach)
  • Self Register Form (FormGroup Approach)
  • Context Service (RxJs Approach)
  • Angular Input Output Handling (Input Out Approach)
  • Angular Two Way binding Approach (Input Out Approach)
  • NgRx Store Approach (Redux Approach)

Form Group as Parameter

Self Register Form Group

The mother form is required to provide the addControl mechanism to the form when the child form is initialized and destroyed. For example, the ngFor and ngIf situation should be catered.

Mother Form

abstract class MotherForm {
  form: FormGroup;
  constructor(){
    this.from = this.initializeForm();
  }

  initializeForm(): FormGroup {
    return new FormGroup({})
  }
  addControlGroup(name: string, formGroup: AbstractControl): void {
    this.form.addControl(name, formGroup);
  }
  removeControl(name: string){
    this.form.removeControl(name);
  }
}

Enter fullscreen mode Exit fullscreen mode

Children Form

abstract class ChildrenForm implements OnInit, OnDestroy {
  @Input()
  intialValue: any
  form: FormGroup
  constructor(@Host private _motherForm: MotherForm){
    this.form = this.initializeForm();
  }
  initializeForm() : FormGroup{
    return new FormGroup({});
  }
  getFormName(): string {
    return 'emptyForm'
  }
  ngOnInit(){
    if (this.intialValue){
      this.form.setValue(this.initialValue)
    }
    this._motherForm.addControlGroup(this.getFormName(), this.form);
  }
  ngOnDestroy(){
    this._motherForm.removeControlGroup(this.getFormName());
  }
}
Enter fullscreen mode Exit fullscreen mode

Now, The implementation class would leverage these abstract class for self registration.

app-self-register.component.ts

import { Component, OnInit } from '@angular/core';
import MotherForm from './mother-form';
import { FormGroup, FormControl } from '@angular/forms';
@Component({
  selector: 'app-self-register',
  templateUrl: './self-register.component.html',
  styleUrls: ['./self-register.component.css']
})
export class SelfRegisterComponent extends MotherForm {
  constructor() {
   super();
  }
  initializeForm(){
    return new FormGroup({
      name: new FormControl('')
    })
  }
}
Enter fullscreen mode Exit fullscreen mode

app-self-register.component.html

<form [formGroup]="form">
  <input formControlName="name"/>
  <app-self-register-children1></app-self-register-children1>
</form>
{{form.value | json}}

Enter fullscreen mode Exit fullscreen mode

self-register-children1.component.ts

import { FormGroup, FormControl } from '@angular/forms';
import { Component, OnInit, Host } from '@angular/core';
import ChildrenForm from '../children-form';
import { SelfRegisterComponent } from '../self-register.component';
@Component({
  selector: 'app-self-register-children1',
  templateUrl: './self-register-children1.component.html',
  styleUrls: ['./self-register-children1.component.css']
})
export class SelfRegisterChildren1Component extends ChildrenForm  {
  constructor(@Host() _motherForm: SelfRegisterComponent) {
    super(_motherForm);
  }
  initializeForm(): FormGroup{
    return new FormGroup({
      name: new FormControl('')
    })
  }
  getFormName(): string {
    return "selfRegisterChildren1";
  }
}

Enter fullscreen mode Exit fullscreen mode

self-register-children1.component.html

<form [formGroup]="form">
  <input formControlName="name"/>
</form>

Enter fullscreen mode Exit fullscreen mode

Result

Reference

Top comments (4)

Collapse
 
anduser96 profile image
Andrei Gatej

Thanks for sharing!

Where would you put those form files?
My first intention would be to put them somewhere in the ‘shared’ folder.
What do you think?

Collapse
 
imben1109 profile image
Ben • Edited

All my source code put on
github.com/TechOffice/TechOffice-A...
FYR, This article would have another parts for below approach.

  • Context Service (RxJs Approach)
  • Angular Input Output Handling (Input Out Approach)
  • Angular Two Way binding Approach (Input Out Approach)
  • NgRx Store Approach (Redux Approach)

Thank a lot.

Collapse
 
anduser96 profile image
Andrei Gatej

I’ve explored a little bit the repo and I’m wondering what’s the use case for the @Host decorator?(I’m referring to this article).
I’ve read a little bit about it but I can’t really understand why you decided to use it.

Could you please elaborate on that?

Thank you!

Thread Thread
 
imben1109 profile image
Ben • Edited

You could refer to the below link for detail.
medium.com/frontend-coach/self-or-...

@host is a decorator for DI Framework in angular to guide angular component to search for expected instance to inject.

If the expected instance cannot be found in the component, it would try to find from the parent component.