Angular 10 strict mode: AbstractControl vs FormControl
Asked Answered
C

4

7

I have this custom component :

<my-component [control]="..."></my-component>

Here, control is defined as :

@Input() control: FormControl;

Usage of my-component :

this.myFormGroup = new FormGroup({
    name: new FormControl('')
});

<my-component [control]="myFormGroup.controls.name"></my-component>

The Error:

Angular 10 strict mode complains about "myFormGroup.controls.name" not being a FormControl.

"controls" is defined in FormGroup as an object where every field is of type AbstractControl :

// forms.d.ts
export declare class FormGroup extends AbstractControl {
    controls: {
        [key: string]: AbstractControl;
    };
    // ....
}

This code would work at runtime but doesn't compile.

What would be the best way to solve this?

Cyclops answered 30/6, 2020 at 17:19 Comment(1)
I understand Strict Mode is supposed to be the better way of doing things but getting around really simple operations like the answers suggest seem really hacky to me. Does anyone know how Angular officially recommends this be done?Conglomeration
I
2

I've avoided this in the past by keeping a reference to the form control outside of the form group.

Eg:

this.nameControl = new FormControl()
this.myFormGroup = new FormGroup({
    name: this.nameControl,
});
Ine answered 30/6, 2020 at 17:24 Comment(0)
N
2

Another aproach is use a setter in input. In your component(*)

  control:FormControl //declare a variable
  @Input('control') set _control(value:AbstractControl) //<--here expect an AbstracControl
  {
    this.control=value as FormControl
  }

A fool example in stackblitz

(*) I choose the way @Input('control') set anyfunctionName to not change your component

Negotiable answered 30/6, 2020 at 19:7 Comment(0)
P
1

You can use AbstractControl method get() to access a control in combination with a TypeScript class get function:

get name() {
  return this.myFormGroup.get('name') as FormControl
}

You can then access the control easily in templates:

<div>{name.value} {name.valid}</div>

This is described in the documentation on Reactive Forms

Hopefully that helps!

Pyrethrin answered 30/6, 2020 at 17:36 Comment(2)
This would work, but I don't like the idea of invoking methods inside the template on every change detection cycle. There's also this solution, it uses a pipe, which should be more performant.Cyclops
@Cyclops Sure you can technically use a pipe, but you are not dealing with primitive values such as strings, numbers, etc. FormControl is not a pure, simple value. Similar to how you should not use pipes for filtering/sorting as also would not be pure. This comes from the official angular documentation.Pyrethrin
S
0

Now you use angular type form. Example

U have object interface for a book.

interface Book { id: number name: string author: string }

U want create a form to edit name and author properties.

Define a type type Form = FormGroup<Partial<{[K in keyof Book]:FormControl}>>

Declare a form public form : Form

Try!

Saintsimon answered 6/6, 2023 at 22:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.