ng-typesafe-formgroup
v0.0.5
Published
A ligthweight (just 19kb) Angular Reactive Form package that makes it's controls type safe and values asserted.
Downloads
5
Maintainers
Readme
Angular TypeSafe Reactive Forms
Reactive FormGroups Wrapped in a Type Safe Class
- Improvements suggesions, bugs, errors, pull requests or become a contributor? Everything you need: https://github.com/pheetah/Angular-Type-Safe-Reactive-FormGroup
- Check this examples on stackblitz: https://stackblitz.com/edit/ng-typesafe-formgroup?file=src%2Fapp%2Fapp.component.html,src%2Fapp%2Fapp.component.ts
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!
typeSafeFormGroupTypedWeak = new FormGroupTypeSafe({
x: new FormControl('', [Validators.required])
});
constructor(){}
ngOnInit(){
this.typeSafeFormGroupTypedWeak.controls.x /* OK!
this.typeSafeFormGroupTypedWeak.controls.a /* X->error! a is not a member of constructor object
}
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:
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!
})