Search code examples
angularangular-reactive-formsangular2-formsangular2-changedetectionangular-changedetection

OnPush change detection when using a FormArray in a service


Fellow developers,

I've got a service that stores a FormArray, which is appended to by one component and viewed by a different component. Even though, the FormArray is immutable and being reassigned to, the view is not updating successfully.

The issue goes away when not using OnPush change detection, or if change detection is force refreshed using changeDetectorRef.detectChanges(). Both of these solutions feel hacky though, and I don't really understand why it's not working as it should.

Sample repo with the issue: https://stackblitz.com/edit/angular-9hwgcn?file=src/app/app.component.html (after adding an item, the list of shopping items doesn't update)


Solution

  • ChangeDetectionStrategy.OnPush stops the automatic change detection as you've experienced. Its use case is primarily input/output components; it tells them to detect changes only when an @Input changes.

    That being said, when I look at your code,

    • you don't have an @Input component
    • your components doesn't have parent/child relationship
    • you're doing a global operation

    and you stop the automatic change detection. In this case you have to tell Angular that there's a change to be detected.

    So no it's not hacky and yes it's working as it should.

    Nevertheless, if you want to avoid all that and want your code to be more reactive you can maybe use observables/subjects. Here's an example:

    export class ShoppingListService {
      shoppingListForm: BehaviorSubject<FormArray> = new BehaviorSubject(
        this.fb.array([])
      );
    
    <ng-container *ngIf="shoppingListService.shoppingListForm | async as shoppingListForm">
      <div class="course-item" *ngFor="let shoppingListItem of shoppingListForm.controls">
        <p>{{ shoppingListItem.value | json }}</p>
      </div>
    </ng-container>
    

    Stackblitz