Repository: angular
Issue: FormArray value changes after valueChanges fires.
Labels: area: forms,state: confirmed,P4

# 🐞 `FormArray.value` changes after `valueChanges` fires.

### Affected Package

(Reactive) Forms, most likely.


### Is this a regression?

I can see the same behaviour on Angular 7, so most likely it's always been this way.


### Description

1. I have a `FormGroup`, which in turn has a `FormArray` control:

```lang=typescript
readonly form = this.formBuilder.group({
  array: this.formBuilder.array([])
});
```

2. This is how I use the form in the template:

```lang=html
<form [formGroup]="form">
  <label *ngFor="let item of form['controls'].array['controls']">
    Name:
    <input [formControl]="item">
  </label>
</form>
```

2. I subscribe to `FormArray.valueChanges`:

```lang=typescript
this.form.get("array").valueChanges.subscribe(value => {
  console.log(value);
});
```

3. I push a new control to the `FormArray` using `.push()`:

```lang=typescript
(this.form.get("array") as FormArray).push(
  this.formBuilder.control('test')
);
```

4. `FormArray.valueChanges` fires as expected, I get my value which is:

```lang=typescript
['test']
```

5. Here's the weird part. If I set a short timeout and try to read the array value using `FormArray.value`, I get a different array. It looks the same (`['test']`), but it is a different array. This only happens once, and after that the value remains stable. See:

```lang=typescript
arrayControl.valueChanges.subscribe(value => {
  console.log(1, arrayControl.value === value); // TRUE - expected, I get the current value

  setTimeout(() => {
    const z = arrayControl.value;
    console.log(2, z === value); // FALSE - UNEXPECTED, the value changed!

    setTimeout(() => {
      console.log(3, arrayControl.value === z); // TRUE - the value no longer changes (the timeout is 1s)
    }, 1000);
  });
});
```

This is related to the form directives. If I use an empty template, then all three log statements print TRUE. Actually, it is enough to remove `<input [formControl]="item">` from the template to get the expected behaviour. It is also irrelevant whether there is a parent form group (`<form [formGroup]="form">`) or not.

Apparently the `.value` field is _not_ a getter, so it must be that the value is explicitly changed by the directives.

I am able to demonstrate the same problem with `FormGroup`s.

## Why is this a problem?

I have a rather complex form, where the data entered in one part of the form creates a basis for selection in other parts of the form. These "other parts" are components which take the array value as an input:

```lang=html
<app-custom-form-component
    formControlName="selection"
    [options]="form['controls'].options.value"
></app-custom-form-component>
```

Because of this unexpected `value` change, the `OnChange` logic is executed twice in the custom component. I also get an `ExpressionChangedAfterItHasBeenCheckedError` as a side-effect.


## 🔬 Minimal Reproduction

`FormArray` example: https://stackblitz.com/edit/angular-ivy-aq9smo?file=src%2Fapp%2Fapp.component.ts.

`FormGroup` example: https://stackblitz.com/edit/angular-ivy-xserr3?file=src%2Fapp%2Fapp.component.html


## 🌍  Your Environment

<pre><code>
{
  "name": "angular",
  "version": "0.0.0",
  "private": true,
  "dependencies": {
    "@angular/animations": "^11.0.8",
    "@angular/common": "^11.0.8",
    "@angular/compiler": "^11.0.8",
    "@angular/core": "^11.0.8",
    "@angular/forms": "^11.0.8",
    "@angular/platform-browser": "^11.0.8",
    "@angular/platform-browser-dynamic": "^11.0.8",
    "@angular/router": "^11.0.8",
    "rxjs": "^6.6.3",
    "tslib": "^2.1.0",
    "zone.js": "^0.11.3"
  },
  "scripts": {
    "ng": "ng",
    "start": "ng serve",
    "build": "ng build",
    "test": "ng test",
    "lint": "ng lint",
    "e2e": "ng e2e"
  },
  "devDependencies": {
    "@angular-devkit/build-angular": "~0.1100.4",
    "@angular/cli": "~11.0.4",
    "@angular/compiler-cli": "~11.0.4",
    "@types/jasmine": "~3.6.0",
    "@types/node": "^12.11.1",
    "codelyzer": "^6.0.0",
    "jasmine-core": "~3.6.0",
    "jasmine-spec-reporter": "~5.0.0",
    "karma": "~5.1.0",
    "karma-chrome-launcher": "~3.1.0",
    "karma-coverage": "~2.0.3",
    "karma-jasmine": "~4.0.0",
    "karma-jasmine-html-reporter": "^1.5.0",
    "protractor": "~7.0.0",
    "ts-node": "~8.3.0",
    "tslint": "~6.1.0",
    "typescript": "~4.0.2"
  }
}
</code></pre>