Skip to content

Commit 628b0c1

Browse files
cexbrayatkara
authored andcommitted
feat(forms): formControlName also accepts a number (#30606)
This commit relaxes the type of the `formControlName` input to accept both a `string` and a `number`. Currently, when using a `FormArray`, most templates look like: ``` <div formArrayName="tags"> <div *ngFor="let tag of tagsArray.controls; index as i"> <input [formControlName]="i"> </div> </div> ``` Here `formControlName` receives a number whereas its input type is a string. This is fine for VE and `fullTemplateTypeCheck`, but not for Ivy which does a more thorough type checking on inputs with `fullTemplateTypeCheck` enabled and throws `Type 'number' is not assignable to type 'string'`. It is fixable by using `formControlName="{{i}}"` but you have to know the difference between `a="{{b}}"` and `[a]="b"` and change it all over the application codebase. This commit allows the existing code to still type-check. PR Close #30606
1 parent e4d5102 commit 628b0c1

File tree

4 files changed

+13
-7
lines changed

4 files changed

+13
-7
lines changed

packages/forms/src/directives/ng_control.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ export abstract class NgControl extends AbstractControlDirective {
3636
* @description
3737
* The name for the control
3838
*/
39-
name: string|null = null;
39+
name: string|number|null = null;
4040

4141
/**
4242
* @description

packages/forms/src/directives/reactive_directives/form_control_name.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -145,9 +145,13 @@ export class FormControlName extends NgControl implements OnChanges, OnDestroy {
145145
* @description
146146
* Tracks the name of the `FormControl` bound to the directive. The name corresponds
147147
* to a key in the parent `FormGroup` or `FormArray`.
148+
* Accepts a name as a string or a number.
149+
* The name in the form of a string is useful for individual forms,
150+
* while the numerical form allows for form controls to be bound
151+
* to indices when iterating over controls in a `FormArray`.
148152
*/
149153
// TODO(issue/24571): remove '!'.
150-
@Input('formControlName') name !: string;
154+
@Input('formControlName') name !: string | number | null;
151155

152156
/**
153157
* @description
@@ -238,7 +242,9 @@ export class FormControlName extends NgControl implements OnChanges, OnDestroy {
238242
* Returns an array that represents the path from the top-level form to this control.
239243
* Each index is the string name of the control on that level.
240244
*/
241-
get path(): string[] { return controlPath(this.name, this._parent !); }
245+
get path(): string[] {
246+
return controlPath(this.name == null ? this.name : this.name.toString(), this._parent !);
247+
}
242248

243249
/**
244250
* @description

packages/forms/src/directives/shared.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ import {SelectMultipleControlValueAccessor} from './select_multiple_control_valu
2828
import {AsyncValidator, AsyncValidatorFn, Validator, ValidatorFn} from './validators';
2929

3030

31-
export function controlPath(name: string, parent: ControlContainer): string[] {
32-
return [...parent.path !, name];
31+
export function controlPath(name: string | null, parent: ControlContainer): string[] {
32+
return [...parent.path !, name !];
3333
}
3434

3535
export function setUpControl(control: FormControl, dir: NgControl): void {

tools/public_api_guard/forms/forms.d.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,7 @@ export declare class FormControlName extends NgControl implements OnChanges, OnD
255255
readonly formDirective: any;
256256
isDisabled: boolean;
257257
/** @deprecated */ model: any;
258-
name: string;
258+
name: string | number | null;
259259
readonly path: string[];
260260
/** @deprecated */ update: EventEmitter<any>;
261261
readonly validator: ValidatorFn | null;
@@ -353,7 +353,7 @@ export declare const NG_VALUE_ACCESSOR: InjectionToken<ControlValueAccessor>;
353353

354354
export declare abstract class NgControl extends AbstractControlDirective {
355355
readonly asyncValidator: AsyncValidatorFn | null;
356-
name: string | null;
356+
name: string | number | null;
357357
readonly validator: ValidatorFn | null;
358358
valueAccessor: ControlValueAccessor | null;
359359
abstract viewToModelUpdate(newValue: any): void;

0 commit comments

Comments
 (0)