Reactive Reactive Forms for Angular 2+. Declarative reactive form validation and disabling.
Run this command:
npm i --save ngx-rrforms
This library aims to improve the reactivity of Angular's inbuilt reactive forms by providing a simple utility in the
form of the RRForm
class that greatly simplifies implementing conditional behaviour (eg. conditional rendering,
validation) that depends on the form's own valueChanges
or outside observables.
In the below examples, a field is displayed only when its status is not DISABLED
.
Below code shows the simplest way RRForm
can be used, which is to disable and enable a control depending on another
control's value.
import {Component, OnDestroy} from '@angular/core';
import {RRForm} from "ngx-rrforms";
import {FormBuilder, FormGroup} from "@angular/forms";
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnDestroy {
constructor(private fb: FormBuilder) {
this.formGroup = this.fb.group({
name: '',
surname: {value: '', disabled: true},
})
this.rr = new RRForm(this.formGroup);
this.rr.control('surname').disable().when((value) => value.name?.length < 5);
}
ngOnDestroy(): void {
this.rr.destroy();
}
rr: RRForm;
formGroup: FormGroup
}
The above code will disable the surname control if the length of the name
control's value is less than 5. It will
re-enable it if it's equal to or more than five.
This is how it works live:
The code below implements the simplest use of conditional addition and removal of validators from controls.
import {Component, OnDestroy, OnInit} from '@angular/core';
import {RRForm} from "ngx-rrforms";
import {FormBuilder, FormGroup, Validators} from "@angular/forms";
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnDestroy {
constructor(private fb: FormBuilder) {
this.formGroup = this.fb.group({
name: '',
surname: {value: '', disabled: true},
})
this.rr = new RRForm(this.formGroup);
this.rr.control('surname').disable().when((value) => value.name?.length < 5);
this.rr.control('surname').validate().when(
{
logic: [(value) => value.name?.length > 7],
validators: [Validators.maxLength(6), Validators.required]
},
);
}
ngOnDestroy(): void {
this.rr.destroy();
}
rr: RRForm;
formGroup: FormGroup
}
In the above code, the surname
control will be disabled on the same condition as in the previous example, but in
addition to that, if the length of the name
control's value is greater than 5, it will add the maxlength
and required
validators to the surname
control.
The default observable that updates the form is its own valueChanges
observable. However, if you'd like the form to
react to outside events, instead of using when
, use whenEvent
. You can use the addObservable
method to add an
observable the form can react to.
import {Component, OnDestroy, OnInit} from '@angular/core';
import {RRForm} from "ngx-rrforms";
import {FormBuilder, FormGroup, Validators} from "@angular/forms";
import {interval, observable} from "rxjs";
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnDestroy {
constructor(private fb: FormBuilder) {
this.formGroup = this.fb.group({
name: '',
surname: {value: '', disabled: true},
})
this.rr = new RRForm(this.formGroup);
this.rr.addObservable('test', this.obs);
this.rr.control('surname').validate().when(
{
logic: [(value) => value.name?.length > 7],
validators: [Validators.maxLength(6), Validators.required]
},
);
this.rr.control('surname').disable().whenEvent('test', (value) => value % 2 == 0)
}
ngOnDestroy(): void {
this.rr.destroy();
}
rr: RRForm;
obs = interval(300)
formGroup: FormGroup
}
In the above example, the obs
observable emits a value every 300ms. If the value emitted is even, the surname
field
will be disabled. You can add conditional validators depending on outside events angalogically.
-
constructor
RRForm(control: AbstractControl)
The main class, the constructor takes in an
AbstractControl
object representing the form where conditional logic will be performed.\When changes are detected in the control passed into the constructor, logic from the
disable()
andvalidate()
will be executed. -
param
path: Array<string | number> | string
- the path to the control as would be used informGroup.get(path: Array<string | number> | string): AbstractControl
Returns an interface to add conditional rules to the control passed in the constructor. The object returned contains two methods,disable()
andvalidate()
. -
Unsubscribes from all the observables used by the
RRForm
object. Make sure to run it insidengOnDestroy()
. -
adds observable and assigns it an event name, to be used with the
whenEvent
methods.
param logicFunctions: ((value: any) => boolean)[]
: an unpacked array of functions of boolean return type.
The value: any
param is the value of the control
passed into the constructor.
-
conditionally disables the specified control if any of the functions passed in return true on form value change
-
re-enables the control if any of the functions passed in return false on form value change
param logic: {logic: ((value: any) => boolean)[], validators: ValidatorFn[]}[]
: an unpacked array of objects, each
containing an array of boolean return type functions in the logic
attribute and an array of ValidatorFn
(eg. Validators.required
) to be added when any of the logic
functions returns true on form value change and removed
when any of them returns false on form value change.
-
conditionally adds validators when any of the functions passed in return true on form value change
-
removes those validators when any of the functions passed in return false on form value change
param eventName: string
: the name of the event (added using RRForm.addObservable
) to which the control should
react.
param logicFunctions: ((value: any) => boolean)[]
: an unpacked array of functions of boolean return type.
The value: any
param is the value emitted by the observable specified by the eventName
param.
-
conditionally disables the specified control if any of the functions passed in return true on observable emission
-
re-enables the control if any of the functions passed in return false on observable emission
param eventName: string
: the name of the event (added using RRForm.addObservable
) to which the control should
react.
param logic: {logic: ((value: any) => boolean)[], validators: ValidatorFn[]}[]
: an unpacked array of objects, each
containing an array of boolean return type functions in the logic
attribute and an array of ValidatorFn
(eg. Validators.required
) to be added when any of the logic
functions returns true and removed when any of them
returns false (they're fired on observable emission). The value: any
param is the value emitted by the observable
specified by the eventName
param.
- conditionally adds validators when any of the functions passed in return true on observable emission
- removes those validators when any of the functions passed in return false on observable emission