Angular Reactive Forms is basically jQuery
Tags: angular, reactiveforms
Published: 2021-03-24 03:27:53

---
title: Angular Reactive Forms is basically jQuery
published: true
description: Angular Reactive Forms makes your code look a lot like jQuery code, even if they're different under the hood.
tags: Angular, ReactiveForms
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xwx6l2qd583tf691i1t0.png
series: Angular Reactive Forms
---
I know they're way different internally, but Angular Reactive Forms makes your code look a lot like jQuery code.

A couple years ago I was assigned to fix a bunch of bugs on a large form that was written in Angular Reactive Forms. The types of bugs that were popping up strongly reminded me of the types of bugs common in jQuery apps. Inconsistent state everywhere!

I suddenly realized how similar the code was to jQuery code. In fact, with only a couple of cosmetic changes, it would have been the same:

![Angular Reactive Forms to jQuery diff](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t7g2qbiwvs9v4xygwuly.png)

This is actually opposed to the pattern Angular traditionally encouraged: Just update variables and set up the DOM to update appropriately. With a single variable update, potentially multiple DOM elements could react all on their own. Now, with reactive forms, you go back to imperative commands for each individual form control... This is a huge step backwards in my opinion.

I know Angular Reactive Forms is the standard answer for forms in Angular, and they are more dynamic than template-driven forms, but I really wanted to go back to the declarative days of old Angular forms. 

Luckily, I wasn’t the only person who noticed that reactive forms needed help to be reactive. Other developers have written articles explaining how to create directives that could hide the imperative interface of reactive forms behind a declarative interface. Check out [this article](https://netbasal.com/disabling-form-controls-when-working-with-reactive-forms-in-angular-549dd7b42110) from Netanel Basal, and [this one](https://medium.com/@amcdnl/reactive-angular-forms-with-ngrx-533a2f28c127) by... Austin.

After using these directives, I never want to go back. 

Here is my own implementation, plus a couple extra directives:

```typescript
// control-disabled.directive.ts
import {Directive, Input} from '@angular/core';
import {NgControl} from '@angular/forms';

@Directive({
    selector: '[controlDisabled]',
})
export class ControlDisabledDirective {
    @Input()
    set controlDisabled(disabled: boolean) {
        const method = disabled ? 'disable' : 'enable';
        this.ngControl.control[method]();
    }

    constructor(private ngControl: NgControl) {}
}
```
```html
<input 
  [formControl]="formControl" 
  [controlDisabled]="disabled$ | async"
/>
```

---
```typescript
// form-group-disabled.directive.ts
import {Directive, Input} from '@angular/core';

@Directive({
    selector: '[formGroupDisabled]',
})
export class FormGroupDisabledDirective {
    @Input() form: any;
    @Input() formGroupName: string;
    @Input()
    set formGroupDisabled(disabled: boolean) {
        const method = disabled ? 'disable' : 'enable';
        this.form.get(this.formGroupName)[method]();
    }
}
```
```html
<div 
  formGroupName="days" 
  [formGroupDisabled]="disabled$ | async"
  [form]="form"
>
```

---
```typescript
// set-value.directive.ts
import {Directive, Input} from '@angular/core';
import {NgControl} from '@angular/forms';

@Directive({
    selector: '[setValue]',
})
export class SetValueDirective {
    @Input()
    set setValue(val: any) {
        this.ngControl.control.setValue(val);
    }

    constructor(private ngControl: NgControl) {}
}
```
```html
<input 
  [formControl]="control" 
  [setValue]="value$ | async" 
/>
```

---
```typescript
// patch-form-group-values.directive.ts
import {Directive, Input} from '@angular/core';

@Directive({
    selector: '[patchFormGroupValues]',
})
export class PatchFormGroupValuesDirective {
    @Input() formGroup: any;
    @Input()
    set patchFormGroupValues(val: any) {
        if (!val) return;
        this.formGroup.patchValue(val, {emitEvent: false});
    }
}
```
```html
<form 
  [formGroup]="scheduleForm" 
  [patchFormGroupValues]="formData$ | async"
>
```
Notice the `{emitEvent: false}` in this one. I was subscribing to `valueChanges` on the form group, so this prevented it from entering an infinite loop, which I think actually shows up as a change detection error. I gave a talk at a meetup and someone said they ran into the error, and I forgot what I did to fix it. I think `{emitEvent: false}` was what fixed it. 

The same thing probably applies to the `setValue` directive, but I haven't tested it, because I recommend just doing explicit state management for the whole form and using `patchFormGroupValues`. 

Hope this helps!

---
Thanks for reading. This was my first post on dev.to. I was expanding on part of [a post I made over on medium.](https://betterprogramming.pub/angular-isnt-reactive-enough-70b6b8d6cf8) That one was behind a paywall, and the editors mutilated the beginning, so I decided to redo the Reactive Forms section here because it was my favorite part and I think it deserved more attention.