### File

`src/lib/form-array.ts`

### Extends

`UntypedFormArray`

### Implements

`AbstractControl`

### Index

###### Properties
Public Readonly controlId Public controls Public Readonly dirty$ Public Readonly disabled$ Public Readonly enabled$ Public Readonly errors Public Readonly errors$ Public Readonly status Public Readonly status$ Public Readonly statusChanges Public Readonly touch$ Public Readonly value Public Readonly value$ Public Readonly valueChanges
###### Methods
Public at Public disabledWhile Public enabledWhile Public getError Public getRawValue Public hasError Public hasErrorAndDirty Public hasErrorAndTouched Public insert Public insertAt Public markAllAsDirty Public markAllAsPristine Public markAllAsUntouched Public markAsDirty Public markAsPristine Public markAsTouched Public markAsUntouched Public mergeAsyncValidators Public mergeValidators Public patchValue Public push Public removeAt Public reset Public select Public setAsyncValidators Public setControl Public setDisable Public setEnable Public setErrors Public setValidators Public setValue Public validateOn
###### Accessors
readonly controlPath fullControlPath

### Constructor

`constructor(controls: Array<AbstractControl<T>>, options: FormArrayOptions)`
Defined in src/lib/form-array.ts:128
Parameters :
Name | Type | Optional
controls | `Array<AbstractControl<T>>` | No
options | `FormArrayOptions` | No

### Properties

Public Readonly controlId
Type : `string`
Defined in src/lib/form-array.ts:117

Public controls
Type : `Array<AbstractControl<T>>`
Defined in src/lib/form-array.ts:131

Public Readonly dirty$
Default value : `this.dirtyChanges .asObservable() .pipe(distinctUntilChanged())`
Defined in src/lib/form-array.ts:123

Public Readonly disabled$
Default value : `controlDisabled$(this)`
Defined in src/lib/form-array.ts:111

Public Readonly enabled$
Default value : `controlEnabled$(this)`
Defined in src/lib/form-array.ts:113

Public Readonly errors
Type : `E | null`
Defined in src/lib/form-array.ts:114

Public Readonly errors$
Default value : `controlErrorChanges$<E>(this)`
Defined in src/lib/form-array.ts:116

Public Readonly status
Type : `ControlState`
Defined in src/lib/form-array.ts:110

Public Readonly status$
Default value : `controlStatusChanges$(this)`
Defined in src/lib/form-array.ts:115

Public Readonly statusChanges
Type : `Observable<ControlState>`
Defined in src/lib/form-array.ts:112

Public Readonly touch$
Default value : `this.touchChanges .asObservable() .pipe(distinctUntilChanged())`
Defined in src/lib/form-array.ts:119

Public Readonly value
Type : `T[]`
Defined in src/lib/form-array.ts:95

Public Readonly value$
Default value : `controlValueChanges$<T[]>(this)`
Defined in src/lib/form-array.ts:109

Public Readonly valueChanges
Type : `Observable<T[]>`
Defined in src/lib/form-array.ts:107

### Methods

Public at
`at(index: number)`
Defined in src/lib/form-array.ts:145
Parameters :
Name | Type | Optional
index | `number` | No
Returns : `AbstractControl<T>`

Public disabledWhile
`disabledWhile(observable: Observable, options?: ControlOptions)`
Defined in src/lib/form-array.ts:192
Parameters :
Name | Type | Optional
observable | `Observable<boolean>` | No
options | `ControlOptions` | Yes
Returns : `any`

Public enabledWhile
`enabledWhile(observable: Observable, options?: ControlOptions)`
Defined in src/lib/form-array.ts:199
Parameters :
Name | Type | Optional
observable | `Observable<boolean>` | No
options | `ControlOptions` | Yes
Returns : `any`

Public getError
`getError(errorCode: K, path?: ControlPath)`
Defined in src/lib/form-array.ts:391
Type parameters : K
Parameters :
Name | Type | Optional
errorCode | `K` | No
path | `ControlPath` | Yes
Returns : `E[K]`

Public getRawValue
`getRawValue()`
Defined in src/lib/form-array.ts:149
Returns : `T[]`

Public hasError
`hasError(errorCode: ExtractStrings<E>, path?: ControlPath)`
Defined in src/lib/form-array.ts:383
Parameters :
Name | Type | Optional
errorCode | `ExtractStrings<E>` | No
path | `ControlPath` | Yes
Returns : `any`

Public hasErrorAndDirty
`hasErrorAndDirty(errorCode: ExtractStrings<E>, path?: ControlPath)`
Defined in src/lib/form-array.ts:302
Parameters :
Name | Type | Optional
errorCode | `ExtractStrings<E>` | No
path | `ControlPath` | Yes
Returns : `boolean`

Public hasErrorAndTouched
`hasErrorAndTouched(errorCode: ExtractStrings<E>, path?: ControlPath)`
Defined in src/lib/form-array.ts:250
Parameters :
Name | Type | Optional
errorCode | `ExtractStrings<E>` | No
path | `ControlPath` | Yes
Returns : `boolean`

Public insert
`insert(index: number, control: AbstractControl<T>)`
Defined in src/lib/form-array.ts:153
Parameters :
Name | Type | Optional
index | `number` | No
control | `AbstractControl<T>` | No
Returns : `void`

Public insertAt
`insertAt(index?: number, state?: T, options?: ControlEventOptions)`
Defined in src/lib/form-array.ts:168
inserts a new control at the specified index. If the index is undefined the new control will be added to the end. Parameters :
Name | Type | Optional | Description
index | `number` | Yes | (optional) the index where the control should be created
state | `T` | Yes | (optional) the initial state of the new control
options | `ControlEventOptions` | Yes | (optional) ControlEventOptions
Returns : `void`

Public markAllAsDirty
`markAllAsDirty()`
Defined in src/lib/form-array.ts:218
Returns : `void`

Public markAllAsPristine
`markAllAsPristine()`
Defined in src/lib/form-array.ts:222
Returns : `void`

Public markAllAsUntouched
`markAllAsUntouched()`
Defined in src/lib/form-array.ts:240
Returns : `void`

Public markAsDirty
`markAsDirty(opts?: OnlySelf)`
Defined in src/lib/form-array.ts:354
Parameters :
Name | Type | Optional
opts | `OnlySelf` | Yes
Returns : `void`

Public markAsPristine
`markAsPristine(opts?: OnlySelf)`
Defined in src/lib/form-array.ts:349
Parameters :
Name | Type | Optional
opts | `OnlySelf` | Yes
Returns : `void`

Public markAsTouched
`markAsTouched(opts?: OnlySelf)`
Defined in src/lib/form-array.ts:339
Parameters :
Name | Type | Optional
opts | `OnlySelf` | Yes
Returns : `void`

Public markAsUntouched
`markAsUntouched(opts?: OnlySelf)`
Defined in src/lib/form-array.ts:344
Parameters :
Name | Type | Optional
opts | `OnlySelf` | Yes
Returns : `void`

Public mergeAsyncValidators
`mergeAsyncValidators(validators: AsyncValidator)`
Defined in src/lib/form-array.ts:210
Parameters :
Name | Type | Optional
validators | `AsyncValidator` | No
Returns : `void`

Public mergeValidators
`mergeValidators(validators: Validator)`
Defined in src/lib/form-array.ts:206
Parameters :
Name | Type | Optional
validators | `Validator` | No
Returns : `void`

Public patchValue
`patchValue(valueOrObservable: any, options?: ControlEventOptions)`
Defined in src/lib/form-array.ts:289
Parameters :
Name | Type | Optional
valueOrObservable | `any` | No
options | `ControlEventOptions` | Yes
Returns : `Subscription | void`

Public push
`push(control: AbstractControl<T>, options?: ControlEventOptions)`
Defined in src/lib/form-array.ts:321
Parameters :
Name | Type | Optional
control | `AbstractControl<T>` | No
options | `ControlEventOptions` | Yes
Returns : `void`

Public removeAt
`removeAt(index: number)`
Defined in src/lib/form-array.ts:309
Parameters :
Name | Type | Optional
index | `number` | No
Returns : `void`

Public reset
`reset(value?: T[], options?: ControlEventOptions)`
Defined in src/lib/form-array.ts:359
Parameters :
Name | Type | Optional
value | `T[]` | Yes
options | `ControlEventOptions` | Yes
Returns : `void`

Public select
`select(mapFn: (state: T[]) => void)`
Defined in src/lib/form-array.ts:141
Type parameters : R
Parameters :
Name | Type | Optional
mapFn | `function` | No
Returns : `Observable<R>`

Public setAsyncValidators
`setAsyncValidators(newValidator: AsyncValidator, updateValueAndValidity)`
Defined in src/lib/form-array.ts:373
Parameters :
Name | Type | Optional | Default value
newValidator | `AsyncValidator` | No |
updateValueAndValidity |  | No | `true`
Returns : `void`

Public setControl
`setControl(index: number, control: AbstractControl<T>, options?: ControlEventOptions)`
Defined in src/lib/form-array.ts:332
Parameters :
Name | Type | Optional
index | `number` | No
control | `AbstractControl<T>` | No
options | `ControlEventOptions` | Yes
Returns : `void`

Public setDisable
`setDisable(disable, opts?: ControlEventOptions)`
Defined in src/lib/form-array.ts:328
Parameters :
Name | Type | Optional | Default value
disable |  | No | `true`
opts | `ControlEventOptions` | Yes |
Returns : `void`

Public setEnable
`setEnable(enable, opts?: ControlEventOptions)`
Defined in src/lib/form-array.ts:317
Parameters :
Name | Type | Optional | Default value
enable |  | No | `true`
opts | `ControlEventOptions` | Yes |
Returns : `void`

Public setErrors
`setErrors(errors: Partial | null, opts: EmitEvent)`
Defined in src/lib/form-array.ts:387
Parameters :
Name | Type | Optional | Default value
errors | `Partial<E> | null` | No |
opts | `EmitEvent` | No | `{}`
Returns : `any`

Public setValidators
`setValidators(newValidator: Validator, updateValueAndValidity)`
Defined in src/lib/form-array.ts:363
Parameters :
Name | Type | Optional | Default value
newValidator | `Validator` | No |
updateValueAndValidity |  | No | `true`
Returns : `void`

Public setValue
`setValue(valueOrObservable: T[] | Observable, options?: ControlEventOptions)`
Defined in src/lib/form-array.ts:226
Parameters :
Name | Type | Optional
valueOrObservable | `T[] | Observable<T[]>` | No
options | `ControlEventOptions` | Yes
Returns : `Subscription | void`

Public validateOn
`validateOn(observableValidation: Observable)`
Defined in src/lib/form-array.ts:244
Parameters :
Name | Type | Optional
observableValidation | `Observable<null | object>` | No
Returns : `any`

### Accessors

readonly
get `readonly()`
Defined in src/lib/form-array.ts:63
set `readonly(value: boolean)`
Defined in src/lib/form-array.ts:67
Parameters :
Name | Type | Optional
value | `boolean` | No
Returns : `void`

controlPath
get `controlPath()`
Defined in src/lib/form-array.ts:81

fullControlPath
get `fullControlPath()`
Defined in src/lib/form-array.ts:97

    import {
      AbstractControl as NgAbstractControl,
      UntypedFormArray,
    } from '@angular/forms';
    import {
      AbstractControl,
      AsyncValidator,
      ControlEventOptions,
      ControlOptions,
      ControlPath,
      ControlState,
      EmitEvent,
      ExtractStrings,
      OnlySelf,
      Validator,
    } from './types';
    import {
      distinctUntilChanged,
      map,
    } from 'rxjs/operators';
    import {
      isObservable,
      Observable,
      Subject,
      Subscription,
    } from 'rxjs';
    import {
      controlDisabled$,
      controlDisabledWhile,
      controlEnabled$,
      controlEnabledWhile,
      controlErrorChanges$,
      controlStatusChanges$,
      controlValueChanges$,
      disableControl,
      enableControl,
      hasErrorAndDirty,
      hasErrorAndTouched,
      markAllDirty,
      markAllPristine,
      markAllUntouched,
      mergeControlValidators,
    } from './control-actions';
    import { coerceArray } from '@rxap/utilities';
    import {
      ControlInsertedFn,
      ControlRemovedFn,
      FormArrayOptions,
      FormBuilderFn,
      FormDefinition,
      FormType,
    } from './model';
    import { isDevMode } from '@angular/core';

    export class RxapFormArray<T = any,
      E extends object = any,
      Parent extends object = any>
      extends UntypedFormArray
      implements AbstractControl<T[]> {

      private _readonly = false;

      public get readonly(): boolean {
        return (this.parent as any)?.readonly ?? this._readonly;
      }

      public set readonly(value: boolean) {
        this._readonly = value;
        this.controls.forEach(control => (control as any).stateChanges?.next());
      }

      /**
       * @internal
       */
      public get rxapFormDefinition():
        | (FormType<Parent> & FormDefinition<Parent>)
        | undefined {
        return (this.parent as any).rxapFormDefinition;
      }

      public get controlPath(): string {
        const parent: any = this.parent;
        if (parent) {
          if (parent.controlPath) {
            if (parent === this.root) {
              return this.controlId;
            } else {
              return [ parent.controlPath, this.controlId ].join('.');
            }
          }
        }
        return this.controlId;
      }

      public override readonly value!: T[];

      public get fullControlPath(): string {
        const parent: any = this.parent;
        if (parent) {
          if (parent.fullControlPath) {
            return [ parent.fullControlPath, this.controlId ].join('.');
          }
        }
        return this.controlId;
      }

      public override readonly valueChanges!: Observable<T[]>;

      public readonly value$ = controlValueChanges$<T[]>(this);
      public override readonly status!: ControlState;
      public readonly disabled$ = controlDisabled$(this);
      public override readonly statusChanges!: Observable<ControlState>;
      public readonly enabled$ = controlEnabled$(this);
      public override readonly errors!: E | null;
      public readonly status$ = controlStatusChanges$(this);
      public readonly errors$ = controlErrorChanges$<E>(this);
      public readonly controlId: string;
      private readonly touchChanges = new Subject<boolean>();
      public readonly touch$ = this.touchChanges
                                   .asObservable()
                                   .pipe(distinctUntilChanged());
      private readonly dirtyChanges = new Subject<boolean>();
      public readonly dirty$ = this.dirtyChanges
                                   .asObservable()
                                   .pipe(distinctUntilChanged());
      private readonly _builder: FormBuilderFn;
      private readonly _controlInsertedFn: ControlInsertedFn;
      private readonly _controlRemovedFn: ControlRemovedFn;

      constructor(
        public override controls: Array<AbstractControl<T>>,
        options: FormArrayOptions,
      ) {
        super(controls, options);
        this.controlId = options.controlId;
        this._builder = options.builder;
        this._controlInsertedFn = options.controlInsertedFn;
        this._controlRemovedFn = options.controlRemovedFn;
      }

      public select<R>(mapFn: (state: T[]) => R): Observable<R> {
        return this.value$.pipe(map(mapFn), distinctUntilChanged());
      }

      public override at(index: number): AbstractControl<T> {
        return super.at(index) as AbstractControl<T>;
      }

      public override getRawValue(): T[] {
        return super.getRawValue();
      }

      public override insert(index: number, control: AbstractControl<T>): void {
        if (isDevMode()) {
          console.warn('It is not recommend to use the FormArray.insert method');
        }
        return super.insert(index, control);
      }

      /**
       * inserts a new control at the specified index. If the index is undefined
       * the new control will be added to the end.
       *
       * @param index (optional) the index where the control should be created
       * @param state (optional) the initial state of the new control
       * @param options (optional) ControlEventOptions
       */
      public insertAt(index?: number, state?: T, options?: ControlEventOptions): void {
        const insertIndex = index ?? this.controls.length;
        const controlOrDefinition = this._builder(state, {
          controlId: insertIndex.toFixed(0),
        });

        this._controlInsertedFn(insertIndex, controlOrDefinition);

        if (insertIndex < this.controls.length) {
          // update the control ids for all controls, that are moved.
          for (let i = insertIndex; i < this.controls.length; i++) {
            Reflect.set(this.controls[i], 'controlId', (i + 1).toFixed(0));
          }
        }

        // call the super insert after the update, bc the insert method will
        // trigger a change detection
        if (controlOrDefinition instanceof NgAbstractControl) {
          super.insert(insertIndex, controlOrDefinition, options);
        } else {
          super.insert(insertIndex, controlOrDefinition.rxapFormGroup!, options);
        }
      }

      public disabledWhile(
        observable: Observable<boolean>,
        options?: ControlOptions,
      ) {
        return controlDisabledWhile(this, observable, options);
      }

      public enabledWhile(
        observable: Observable<boolean>,
        options?: ControlOptions,
      ) {
        return controlEnabledWhile(this, observable, options);
      }

      public mergeValidators(validators: Validator) {
        mergeControlValidators(this, validators);
      }

      public mergeAsyncValidators(validators: AsyncValidator) {
        this.setAsyncValidators([
          ...coerceArray(this.asyncValidator),
          ...coerceArray(validators),
        ]);
        this.updateValueAndValidity();
      }

      public markAllAsDirty(): void {
        markAllDirty(this);
      }

      public markAllAsPristine(): void {
        markAllPristine(this);
      }

      public override setValue(
        valueOrObservable: T[] | Observable<T[]>,
        options?: ControlEventOptions,
      ): Subscription | void {
        if (isObservable(valueOrObservable)) {
          return valueOrObservable.subscribe((value) => {
              super.setValue(value, options);
            },
          );
        }

        super.setValue(valueOrObservable, options);
      }

      public markAllAsUntouched(): void {
        markAllUntouched(this);
      }

      public validateOn(observableValidation: Observable<null | object>) {
        return observableValidation.subscribe((maybeError) => {
          this.setErrors(maybeError);
        });
      }

      public hasErrorAndTouched(
        errorCode: ExtractStrings<E>,
        path?: ControlPath,
      ): boolean {
        return hasErrorAndTouched(this, errorCode, path);
      }

      private _patchValue(value: T[], options?: ControlEventOptions) {
        // Even though the `value` argument type doesn't allow `null` and `undefined` values, the
        // `patchValue` can be called recursively and inner data structures might have these values, so
        // we just ignore such cases when a field containing FormArray instance receives `null` or
        // `undefined` as a value.
        if (value == null /* both `null` and `undefined` */) {
          return;
        }
        if (options?.strict) {
          if (this.length > value.length) {
            for (let index = this.length - 1; index >= value.length; index--) {
              this.removeAt(index);
            }
          }
        }
        value.forEach((newValue, index) => {
          if (this.at(index)) {
            this.at(index)
                .patchValue(
                  newValue,
                  {
                    ...(options ?? {}),
                    onlySelf: true,
                  },
                );
          } else if (options?.coerce) {
            this.insertAt(index, value[index]);
          }
        });
        this.updateValueAndValidity(options);
      }

      public override patchValue(
        valueOrObservable: any,
        options?: ControlEventOptions,
      ): Subscription | void {
        if (isObservable(valueOrObservable)) {
          return (valueOrObservable as Observable<T[]>).subscribe((value: T[]) => {
            this._patchValue(value, options);
          });
        }

        this._patchValue(valueOrObservable as T[], options);
      }

      public hasErrorAndDirty(
        errorCode: ExtractStrings<E>,
        path?: ControlPath,
      ): boolean {
        return hasErrorAndDirty(this, errorCode, path);
      }

      public override removeAt(index: number) {
        if (isDevMode()) {
          console.warn('It is not recommend to use the FormArray.removeAt method');
        }
        super.removeAt(index);
        this._controlRemovedFn(index);
      }

      public setEnable(enable = true, opts?: ControlEventOptions) {
        enableControl(this, enable, opts);
      }

      public override push(control: AbstractControl<T>, options?: ControlEventOptions): void {
        if (isDevMode()) {
          console.warn('It is not recommend to use the FormArray.push method');
        }
        return super.push(control, options);
      }

      public setDisable(disable = true, opts?: ControlEventOptions) {
        disableControl(this, disable, opts);
      }

      public override setControl(index: number, control: AbstractControl<T>, options?: ControlEventOptions): void {
        if (isDevMode()) {
          console.warn('It is not recommend to use the FormArray.setControl method');
        }
        return super.setControl(index, control, options);
      }

      public override markAsTouched(opts?: OnlySelf): void {
        super.markAsTouched(opts);
        this.touchChanges.next(true);
      }

      public override markAsUntouched(opts?: OnlySelf): void {
        super.markAsUntouched(opts);
        this.touchChanges.next(false);
      }

      public override markAsPristine(opts?: OnlySelf): void {
        super.markAsPristine(opts);
        this.dirtyChanges.next(false);
      }

      public override markAsDirty(opts?: OnlySelf): void {
        super.markAsDirty(opts);
        this.dirtyChanges.next(true);
      }

      public override reset(value?: T[], options?: ControlEventOptions): void {
        super.reset(value, options);
      }

      public override setValidators(
        newValidator: Validator,
        updateValueAndValidity = true,
      ): void {
        super.setValidators(newValidator);
        if (updateValueAndValidity) {
          super.updateValueAndValidity();
        }
      }

      public override setAsyncValidators(
        newValidator: AsyncValidator,
        updateValueAndValidity = true,
      ): void {
        super.setAsyncValidators(newValidator);
        if (updateValueAndValidity) {
          super.updateValueAndValidity();
        }
      }

      public override hasError(errorCode: ExtractStrings<E>, path?: ControlPath) {
        return super.hasError(errorCode, path);
      }

      public override setErrors(errors: Partial<E> | null, opts: EmitEvent = {}) {
        return super.setErrors(errors, opts);
      }

      public override getError<K extends ExtractStrings<E>>(
        errorCode: K,
        path?: ControlPath,
      ) {
        return super.getError(errorCode, path) as E[K] | null;
      }
    }

# results matching ""

# No results matching ""