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.

FormBuilder.group controls with array values requires an extra [ ]

See original GitHub issue

Which @angular/* package(s) are the source of the bug?

forms

Is this a regression?

Yes

Description

Given the following:

interface FormModel {
  favorites: string[];
}

...

form = this.fb.group<FormModel>({
  favorites: []
})

I would expect the initial form value would be { favorites: [] }, but it results in { favorites: null }. To achieve the expected result, I need the following:

form = this.fb.group<FormModel>({
  favorites: [ [] ]
})

But it produces type-checking errors - same thing happens with NonNullableFormBuilder

Please provide a link to a minimal reproduction of the bug

https://stackblitz.com/edit/angular-ivy-y5vvdq?file=src/app/app.component.ts

Please provide the exception or error you saw

Type '[]' is not assignable to type 'string'.(2322)

Please provide the environment you discovered this bug in (run ng version)

Angular CLI: 14.0.1
Node: 16.13.0
Package Manager: npm 8.12.1 
OS: linux x64

Angular: 14.0.1
... animations, cdk, cli, common, compiler, compiler-cli, core
... forms, material, platform-browser, platform-browser-dynamic
... router

Package                         Version
---------------------------------------------------------
@angular-devkit/architect       0.1303.7
@angular-devkit/build-angular   14.0.1
@angular-devkit/core            13.3.7
@angular-devkit/schematics      14.0.1
@angular/flex-layout            13.0.0-beta.38
@schematics/angular             14.0.1
rxjs                            7.5.5
typescript                      4.7.3

Anything else?

No response

Issue Analytics

  • State:closed
  • Created a year ago
  • Reactions:1
  • Comments:7 (3 by maintainers)

github_iconTop GitHub Comments

2reactions
zstundyscommented, Jun 15, 2022

Seems like using the constructor pattern is not so bad – after making some abstractions:

interface FormModel {
  name: string;
  age: number | undefined;
  favorites: string[]
}

...

@Component(...)
export class FormComponent {
  // Type safe & terse definition for a non-nullable form
  form = buildForm<FormModel>({
    name: [''],
    age: [undefined],
    favorites: [[], [Validators.minLength(1)]]
  });
}
Source code
type ControlsOf<T extends Record<string, any>> = {
  [K in keyof T]: FormControl<T[K]>;
};

type GroupConfig<T> = {
  [K in keyof T]: ControlConfig<T, K>;
};

type ControlConfig<T, K extends keyof T> = readonly [
  initialValue: T[K] | FormControlState<T[K]>,
  validators?: ValidatorFn | ValidatorFn[]
];

export function buildForm<T extends Record<any, any>>(config: GroupConfig<T>): FormGroup<ControlsOf<T>> {
  return new FormGroup(
    Object.entries(config).reduce(
      (acc, [key, [value, validators]]: [keyof T, ControlConfig<T, keyof T>]) => ({
        ...acc,
        [key]: new FormControl(value, { validators, nonNullable: true }),
      }),
      {} as ControlsOf<T>
    )
  );
}
1reaction
dylhunncommented, Jun 14, 2022

Ah interesting. The FormBuilder types are not really set up to handle array-valued FormControls. Because FormBuilder is so implicit, and relies so heavily on inferring what is meant by the arguments, arrays are taken to mean FormArray in all but a few cases.

I suggest not using FormBuilder in this case. I suspect that directly constructing FormControl and FormGroup objects will give you much cleaner results for tricky cases.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Angular - FormBuilder.group not accepting array of validators
On the contrary, Validators.required makes sense, as the value could be null when all controls aren't set. Let's say that you have two...
Read more >
Angular FormArray - Complete Guide
A FormArray , just like a FormGroup , is also a form control container, that aggregates the values and validity state of its...
Read more >
FormBuilder - Angular
The FormBuilder provides syntactic sugar that shortens creating instances of a FormControl , FormGroup , or FormArray . It reduces the amount of...
Read more >
How to Use Angular FormArray(s) within FormGroup(s) In ...
Are you trying to use a FormArray on a dynamic/reactive Angular Form, but it is not working? This should help you solve your...
Read more >
Angular Reactive Forms: The Ultimate Guide to FormArray
A FormArray is responsible for managing a collection of AbstractControl , which can be a FormGroup , a FormControl , or another FormArray...
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