0.0.5 • Published 2 years ago

ng-typesafe-formgroup v0.0.5

Weekly downloads
-
License
MIT
Repository
github
Last release
2 years ago

Angular TypeSafe Reactive Forms

Reactive FormGroups Wrapped in a Type Safe Class

Installation and Basic Usage Guide

Implemented on Angular v13.2.x

Please click on dropdowns below for further information:

npm i ng-typesafe-formgroup
import { FormsModule, ReactiveFormsModule } from '@angular/forms';

@NgModule({
  declarations: [
    ...
  ],
  imports: [
    ...,
    FormsModule,
    ReactiveFormsModule
  ],
  providers: [],
  bootstrap: [...]
})
export class ...Module { }
import { FormControlTypeSafe, FormGroupTypeSafe } from 'ng-typesafe-formgroup';


interface CustomInterface{
  name: string,
  email: string,
  message: number,
};

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent {

  typeSafeFormGroup = new FormGroupTypeSafe<CustomInterface>({
    name: new FormControlTypeSafe<CustomInterface["name"]>('', [Validators.required, Validators.minLength(5)]),
    email: new FormControlTypeSafe<CustomInterface["email"]>('', [Validators.required, Validators.maxLength(30)]),
    message: new FormControlTypeSafe<CustomInterface["message"]>('', [Validators.required, Validators.maxLength(100)])
  });

  \* you can now directly reach the controls! *\
  ngOnInit(){
    this.typeSafeFormGroup.controls.name
    this.typeSafeFormGroup.controls.message
    this.typeSafeFormGroup.controls.email
    this.typeSafeFormGroup.controls.email.value
    this.typeSafeFormGroup.controls.email.valueChanges.subscribe(a => console.log(a));
    this.typeSafeFormGroup.valueChanges.subscribe(a => console.log(a));
  }

}
import { FormControlTypeSafe, FormGroupTypeSafe } from 'ng-typesafe-formgroup';


@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent {
  typeSafeFormGroupTypedWeak = new FormGroupTypeSafe({
    x: new FormControlTypeSafe('', [Validators.required])
  });

  ngOnInit(){
    this.typeSafeFormGroupTypedWeak.controls.x.value
    this.typeSafeFormGroupTypedWeak.controls.x.valueChanges.subscribe(a => console.log(a));
    this.typeSafeFormGroupTypedWeak.valueChanges.subscribe(a => console.log(a));
  }
}
    
  ...
  
  interface CustomInterface{
    name: string,
    email: string,
    message: number,
  };

  ...

  typeSafeFormGroup = new FormGroupTypeSafe<CustomInterface>({
    name: new FormControlTypeSafe<CustomInterface["name"]>('', [Validators.required, Validators.minLength(5)]),
    email: new FormControlTypeSafe<CustomInterface["email"]>('', [Validators.required, Validators.maxLength(30)]),
    message: new FormControlTypeSafe<CustomInterface["message"]>('', [Validators.required, Validators.maxLength(100)])
  });

  ...

and this way forms will asset your values on typeSafeFormGroup.valueChanges and typeSafeFormGroup.value such as ;

 typeSafeFormGroup.valueChanges.subscribe(val => val); \* val asserted as CustomInterface *\
 typeSafeFormGroup.value \* value asserted as CustomInterface \*

so that value is asserted correctly, unlike normal FormGroup class asserts everything as any!

constructor(){}

ngOnInit(){
  this.typeSafeFormGroupTypedWeak.controls.x /* OK!
  this.typeSafeFormGroupTypedWeak.controls.a /* X->error! a is not a member of constructor object
}
    
</li>

<br><br>
</details>

<br />

<br />

<br />

<br />

# Important note

Be careful on value assertions. If you declare and interface and provide it to form group, values asserted on property types of interface. For example:
```ruby
interface CustomInterface{
  name: string,
  email: string,
  message: number,
};

typeSafeFormGroup = new FormGroupTypeSafe<CustomInterface>({
  name: new FormControlTypeSafe<CustomInterface["name"]>('', [Validators.required, Validators.minLength(5)]),
  email: new FormControlTypeSafe<CustomInterface["email"]>('', [Validators.required, Validators.maxLength(30)]),
  message: new FormControlTypeSafe<CustomInterface["message"]>('', [Validators.required, Validators.maxLength(100)])
});

this.typeSafeFormGroup.controls.email.value -> asserted as: string | number , because types on CustomInterfaces are string | number
this.typeSafeFormGroup.controls.email.valueChanges.subscribe(a => console.log(a)); -> 'a' asserted as string | number
this.typeSafeFormGroup.valueChanges.subscribe(a => console.log(a)); -> 'a' asserted as CustomInterface
this.typeSafeFormGroup.value -> asserted as CustomInterface

If you don't provide an interface values asserted as "unknown". If you want to assign the value for example to a string (you expect it coming from the form), just basically do:

  typeSafeFormGroupTypedWeak = new FormGroupTypeSafe({
    x: new FormControlTypeSafe('', [Validators.required])
  });

  let x:string = <unknown> this.typeSafeFormGroupTypedWeak.controls.x.value as string;
  this.typeSafeFormGroupTypedWeak.controls.x.valueChanges.subscribe(a => a);



  this.typeSafeFormGroupTypedWeak.controls.x.value -> asserted as unknown

Please note that you can still use FormControl inside FormGroupTypeSafe instead of FormControlTypeSafe, but it's recommended to use FormControlTypeSafe.

Type safe forms prevents you from making mistakes

  • Transpiler warns you if you try to access an invalid control
  typeSafeFormGroupTypedWeak = new FormGroupTypeSafe({
    x: new FormGroupTypeSafe('', [Validators.required])
  });

  constructor(){}

  ngOnInit(){
    this.typeSafeFormGroupTypedWeak.controls.x /* OK!
    this.typeSafeFormGroupTypedWeak.controls.a /* X->error! a is not a member of constructor object
  }
  • If you provide an interface, you can not define a control that is not defined in the interface you provide
  interface FormControls{
    name: string,
    email: string,
    message: number,
  };

  typeSafeFormGroup = new FormGroupTypeSafe<FormControls>({
    name: new FormControlTypeSafe('', [Validators.required, Validators.minLength(5)]),
    email: new FormControlTypeSafe('', [Validators.required, Validators.maxLength(30)]),
    message: new FormControlTypeSafe('', [Validators.required, Validators.maxLength(100)]),
    outlier: new FormControlTypeSafe('', [Validators.required, Validators.maxLength(100)]) // X-> error! 'outlier' is not  FormControls property!
  })