Intro
In my previous article we changed the reset()
methods of angular forms and added clear()
. This time, we are going to differentiate the user input from the programmer (or code) input.
The how
We have actually two options to do this, both of them require adding at least one new method which we will call: setControlValue()
since we will be changing the FormControl
value:
- Add another method
setInputValue()
which will signify that the input has changed - Use existing
setValue()
as the one for the user input
Since the first option is only viable if you, for some reason, separate input from the forms, we are going the second path which is also easier to implement.
In the setControlValue()
we will enable setting the value even if the control is disabled, because sometimes it's nice to have. We will also use the setValue()
method to change the internal value but we will not trigger the valueChanges
event unless programmer wants it. Hope this becomes clearer with the implementation.
Implementation
Similarly to previous functionality, we first need to declare extra method. We will do that in the AbstractControl
for compatibility with formGroup.get()
method, and in the FormControl
for actual functionality:
declare module "@angular/forms" {
interface AbstractControl {
...
controlValueChanges: EventEmitter<any>;
setControlValue(value: any, options?: {emitEvent?: boolean, emitValueEvent?: boolean});
}
interface FormControl extends AbstractControl {
setControlValue(value: any, options?: {emitEvent?: boolean, emitValueEvent?: boolean});
}
}
In the AbstractControl
we initialize the EventEmitter
and just proxy the setControlValue
arguments to setValue
for compatibility:
AbstractControl.prototype.controlValueChanges = new EventEmitter<any>();
AbstractControl.prototype.setControlValue = function (value: any, options: { emitEvent?: boolean, emitValueEvent?: boolean }): void {
let opt = options ? {emitEvent: options.emitValueEvent} : null;
this.setValue(value, opt);
};
And in the FormControl
we actually implement the desired functionality:
FormControl.prototype.setControlValue = function (value: any, options?: { emitEvent?: boolean, emitValueEvent?: boolean }): void {
if (this.disabled) {
this.enable();
this.setValue(value, {emitEvent: options && options.emitValueEvent});
this.disable();
} else {
this.setValue(value, {emitEvent: options && options.emitValueEvent});
}
if (options && options.emitEvent) {
this.controlValueChanges.emit(value);
}
};
And that's it. We now have an option to override user input even for the disabled control.
Conclusion
This concludes this series. During just few articles, we have extended the Angular Forms quite a bit. We can show and hide controls from a single place (and also do not consider hidden controls for validation), we can reset the control to default value or clear it completely, we can determine whether the value change came from user input or from our internal logic. And it wasn't even that hard when using prototype
.
Obviously there might be some corner cases which I forgot about and it needs a lot more testing, especially automated, but otherwise, it works.
Hope this series will be of use to you and that you learned something new along the way :)
Top comments (0)