What’s RxFormMapper?
RxFormMapper is a framework developed for angular and allows you to convert, by annotation, classes into reactive form and vice versa.
When to use RxFormMapper?
Sometimes you want to transform the classes you have into reactive forms, for example you have a user model that you want to have filled out by a form:
export class User {
name: string;
surname: string;
age: number;
}
So what to do? How to make a user form ? Solution is to create new instances of Reactive Form object and manually assign all properties to new object. But things may go wrong very fast once you have a more complex object hierarchy.
new FormGroup(
name: new FormControl(user.name),
surname: new FormControl(user.surname),
age: new FormControl(user.age),
);
To avoid all this you can use RxFormMapper:
export class User {
@FormControl()
name: string;
@FormControl()
surname: string;
@FormControl()
age: number;
}
Why use RxFormMapper?
RxFormMapper speed up your form development avoiding redundant boilerplate in your code. The most important benefits are:
- Zero configuration: through annotations removes the boilerplate for creating and assigning forms.
- Dependency Injection: RxFormMapper take advantage from Angular DI container in order to resolves validators and custom mappers.
- Custom mappers: If you want to create custom forms for specific fields, you can do it simple by @CustomControl decorator.
Let’s start writing code
Install npm package
npm i rx-form-mapper --save
reflect-metadata
is required (with angular+ you should already have this dependency installed.)
npm i reflect-metadata --save
Import the component modules
Import RxFormMapperModule in your AppModule
// app.module.ts
import { RxFormMapperModule } from 'rx-form-mapper';
@NgModule({
imports: [RxFormMapperModule.forRoot()],
})
export class AppModule { }
Define your model
// user-registration.model.ts
export class UserRegistration {
public name: string;
public surname: string;
public birthday: Date;
public email: string;
public password: string;
public passwordCheck: string;
}
Annotate it
RxFormMapper allow you to specify through annotations the type of AbstractControl for each field in your model, specifically: FormControl, FormGroup and FormArray.
// user-registration.model.ts
import { Validators } from '@angular/forms';
import { FormControl, Form } from 'rx-form-mapper';
import { AlreadySignedAsyncValidator, noWhitespace, passwordCheck } from './app-validators';
@Form({validators: passwordCheck })
export class UserRegistration {
@FormControl({ validators: noWhitespace })
public name: string;
@FormControl({ validators: noWhitespace })
public surname: string;
@FormControl({ validators: Validators.required })
public birthday: Date;
@FormControl({
validators: [Validators.required, Validators.email],
asyncValidators: AlreadySignedAsyncValidator
})
public email: string;
@FormControl({ validators: noWhitespace })
public password: string;
@FormControl({ validators: noWhitespace })
public passwordCheck: string;
}
You can read further informations about RxFormMapper annotations by consulting the github page attached at the beginning of this article.
Wait… AsyncValidators? How to inject services?!
Don’t panic: RxFormMapper automatically resolves all validators registered inside the Angular container for you! 😉
// already-signed-async.validator.ts
@Injectable()
export class AlreadySignedAsyncValidator implements AsyncValidator {
public constructor(private readonly http: HttpClient) {}
validate(control: AbstractControl): Promise<ValidationErrors>|Observable<ValidationErrors> {
if (isWhitespace(control.value)) {
return of(null);
}
return http.get<>('your url').pipe(
map(exists => exists ? ({ alreadySigned: true }) : null)
);
}
}
// app.module.ts
import { RxFormMapperModule } from 'rx-form-mapper';
import { AlreadySignedAsyncValidator } from './validators';
@NgModule({
imports: [RxFormMapperModule.forRoot()],
providers: [AlreadySignedAsyncValidator]
})
export class AppModule { }
Build your form
// app.component.ts
import { Component } from "@angular/core";
import { FormGroup } from "@angular/forms";
import { RxFormMapper } from "rx-form-mapper";
import { UserRegistration } from "./user-registration";
@Component({
selector: "my-app",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.css"]
})
export class AppComponent {
public readonly form: FormGroup;
public constructor(mapper: RxFormMapper) {
this.form = mapper.writeForm(new UserRegistration());
}
}
You can find the sources of this article on stackblitz 😁
Conclusion
RxFormMapper is a great tool that allows you to create reactive forms in a simple and declarative way through the annotations, allowing you to focus on your features. This type of framework is particularly suitable for crud-based applications as it drastically reduces the code to maintain.
If you enjoyed this guide, don’t forget to share it with all the people who might benefit from it 😃
So long, and thanks for all the fish 🐬