Skip to content

Instantly share code, notes, and snippets.

@pdashford
Last active June 28, 2021 12:44
Show Gist options
  • Save pdashford/3e9338cafac51424c6607550eee4c484 to your computer and use it in GitHub Desktop.
Save pdashford/3e9338cafac51424c6607550eee4c484 to your computer and use it in GitHub Desktop.
Custom Angular FormGroup which maintains the initial form state. Provides a valuesChanged Observable which only provides real modified values
import { EventEmitter } from '@angular/core'
import {
FormGroup,
AbstractControl,
ValidatorFn,
AbstractControlOptions,
AsyncValidatorFn
} from '@angular/forms'
/**
*
*
* @export
* @class FormGroupState
* @extends {FormGroup}
*/
export class FormGroupState extends FormGroup {
public readonly valuesChanged!: EventEmitter<any>
private _state = []
private _changed = {}
constructor(
controls: {
[key: string]: AbstractControl
},
validatorOrOpts?:
| ValidatorFn
| ValidatorFn[]
| AbstractControlOptions
| null,
asyncValidator?: AsyncValidatorFn | AsyncValidatorFn[] | null
) {
super(controls, validatorOrOpts, asyncValidator)
this.valuesChanged = new EventEmitter()
this.valueChanges.subscribe((changes) => {
if (this._state.length) {
this._changed = {}
Object.keys(changes)
.filter((key) => this._state.map((m) => m.name).includes(key))
.forEach((controlName) => {
const controlValue = this.controls[controlName].value
if (
controlValue !==
this._state.find((f) => f.name === controlName).value
) {
Object.assign(this._changed, {
[controlName]: controlValue
})
}
})
this.valuesChanged.emit(this._changed)
}
})
}
setInitialState(
value: { [key: string]: any },
options?: {
onlySelf?: boolean
emitEvent?: boolean
}
): void {
super.patchValue(value, options)
this._state = []
Object.keys(this.controls).forEach((name) => {
this._state.push({ name, value: this.controls[name].value })
})
}
get changedValues() {
return this._changed
}
}
/***************************************************************************************************
* Custom FormGroup which maintains an initial form state so that only 'real' changes are reported
*
* Example:
*
* formGroup = new FormGroupState({
* name: new FormControl(''),
* id: new FormControl('')
* })
*
* // Sets the iniitial form values and state
* this.formGroup.setInitialState({ name: 'welcome', id: 0}, { emitEvent: false })
*
* // Only the real changes will be reported here....
* this.formGroup.valuesChanged.subscribe(changes => console.log(changes))
*
/***************************************************************************************************/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment