question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Add replaceControls method to FormArray class

See original GitHub issue

🚀 feature request

Relevant Package

This feature request is for the FormArray class in @angular/form.,

Description

Currently if i use a FormArray in a custom ControlValueAccessor i have to manually remove/add controls based on the writeValues input.

Here is an example:

import { Component, forwardRef, OnDestroy } from '@angular/core';
import { ControlValueAccessor, FormArray, FormControl, NG_VALUE_ACCESSOR } from '@angular/forms';
import { Observable, ReplaySubject, Subscription } from 'rxjs';
import { filter, map, takeUntil } from 'rxjs/operators';

@Component({
    template: `custom-value-accessor-template`,
    selector: 'my-custom-value-accessor',
    providers: [{
        provide: NG_VALUE_ACCESSOR,
        useExisting: forwardRef(() => MyCustomControlValueAccessor),
        multi: true
    }]
})
export class MyCustomControlValueAccessor<TValue extends unknown = unknown> implements ControlValueAccessor,
    OnDestroy {

    protected readonly control = new FormArray([]);
    protected readonly userValueChanges$: Observable<TValue[]>;
    protected readonly destroyed = new ReplaySubject<void>(1);

    private changesSubscription: Subscription | undefined;
    private pauseChanges = false;
    private _changeFn: (change: TValue[]) => void;
    private _touchedFn: () => void;

    constructor() {
        this.userValueChanges$ = this.control.valueChanges.pipe(
            filter(() => !this.pauseChanges),
            map(() => this.control.getRawValue())
        );
    }

    public writeValue(value: TValue[]): void {
        this.pauseChanges = true;

        while (this.control.length > 0) {
            this.control.removeAt(0);
        }

        value.forEach(item => {
            this.control.push(new FormControl(item));
        });

        this.pauseChanges = false;
    }

    public ngOnDestroy(): void {
        this.destroyed.next();
        this.destroyed.complete();
    }

    public registerOnChange(fn: (change: TValue[]) => void): void {
        this._changeFn = fn;

        if (!this.changesSubscription) {
            this.userValueChanges$.pipe(
                takeUntil(this.destroyed)
            ).subscribe(
                val => this.change(val)
            );
        }
    }

    public registerOnTouched(fn: any): void {
        this.touched = fn;
    }

    public change(value: TValue[]): void {
        if (this._changeFn) this._changeFn(value);
    }

    public touched(): void {
        if (this._touchedFn) this._touchedFn();
    }
}

Describe the solution you’d like

It would be nice if the FormArray would implement a replaceControls method:

    /**
     * Replace the current controls with new ones.
     *
     * @usageNotes
     * ### Replace controls of a FormArray
     *
     * ```typescript
     * const arr = new FormArray([
     *   new FormControl(0),
     *   new FormControl(1),
     *   new FormControl(2)
     * ]);
     *
     * console.log(arr.value);   // [1, 2, 0]
     *
     * arr.replaceControls([new FormControl(2)]);
     *
     * console.log(arr.value);   // [2]
     * ```
     *
     * @param controls The new controls which will replace the old ones
     */
    public replaceControls(controls: AbstractControl[]): void {
        if(this.controls.length) {
            this.controls.forEach(control => (control as any)._registerOnCollectionChange(() => undefined));
            this.controls.splice(0);
        }

        controls.forEach(control => {
            this.controls.push(control);
            (this as any)._registerControl(control);
        });

        this.updateValueAndValidity();
        (this as any)._onCollectionChange();
    }

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Reactions:7
  • Comments:6 (3 by maintainers)

github_iconTop GitHub Comments

2reactions
epiphanizercommented, Dec 3, 2019

Glad I’m not the only one wanting this. ha!

0reactions
angular-automatic-lock-bot[bot]commented, Aug 29, 2021

This issue has been automatically locked due to inactivity. Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

Read more comments on GitHub >

github_iconTop Results From Across the Web

How to update controls of FormArray - angular - Stack Overflow
AFAIK putting a FormGroup inside of a FormArray strips the 'FormControls' of their names and makes it just a list, like a normal...
Read more >
Add/Push and Remove Form fields dynamically to FormArray ...
We use the getter method to get us demoArray as FormArray directly from demoForm. It creates the new property named as demoArray so...
Read more >
angular dynamic add form group - You.com | The AI Search ...
Create your FormGroup containing a FormArray. this.formGroup = new FormGroup({ licenses: new FormArray([]) }) · After receiving the data, store it into an...
Read more >
FormArray - Angular
To change the controls in the array, use the push , insert , removeAt or clear methods in FormArray itself. These methods ensure...
Read more >
Angular 2: Can't add form group to form array in reactive Forms
import {Component, OnInit} from '@angular/core'; import {FormGroup, FormBuilder, FormArray, Validators, FormControl} from "@angular/forms"; export class ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found