Skip to content

Commit

Permalink
feat(forms): formControlName also accepts a number (#30606)
Browse files Browse the repository at this point in the history
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
  • Loading branch information
cexbrayat authored and kara committed Aug 13, 2019
1 parent e4d5102 commit 628b0c1
Show file tree
Hide file tree
Showing 4 changed files with 13 additions and 7 deletions.
2 changes: 1 addition & 1 deletion packages/forms/src/directives/ng_control.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export abstract class NgControl extends AbstractControlDirective {
* @description
* The name for the control
*/
name: string|null = null;
name: string|number|null = null;

/**
* @description
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,9 +145,13 @@ export class FormControlName extends NgControl implements OnChanges, OnDestroy {
* @description
* Tracks the name of the `FormControl` bound to the directive. The name corresponds
* to a key in the parent `FormGroup` or `FormArray`.
* Accepts a name as a string or a number.
* The name in the form of a string is useful for individual forms,
* while the numerical form allows for form controls to be bound
* to indices when iterating over controls in a `FormArray`.
*/
// TODO(issue/24571): remove '!'.
@Input('formControlName') name !: string;
@Input('formControlName') name !: string | number | null;

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

/**
* @description
Expand Down
4 changes: 2 additions & 2 deletions packages/forms/src/directives/shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ import {SelectMultipleControlValueAccessor} from './select_multiple_control_valu
import {AsyncValidator, AsyncValidatorFn, Validator, ValidatorFn} from './validators';


export function controlPath(name: string, parent: ControlContainer): string[] {
return [...parent.path !, name];
export function controlPath(name: string | null, parent: ControlContainer): string[] {
return [...parent.path !, name !];
}

export function setUpControl(control: FormControl, dir: NgControl): void {
Expand Down
4 changes: 2 additions & 2 deletions tools/public_api_guard/forms/forms.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ export declare class FormControlName extends NgControl implements OnChanges, OnD
readonly formDirective: any;
isDisabled: boolean;
/** @deprecated */ model: any;
name: string;
name: string | number | null;
readonly path: string[];
/** @deprecated */ update: EventEmitter<any>;
readonly validator: ValidatorFn | null;
Expand Down Expand Up @@ -353,7 +353,7 @@ export declare const NG_VALUE_ACCESSOR: InjectionToken<ControlValueAccessor>;

export declare abstract class NgControl extends AbstractControlDirective {
readonly asyncValidator: AsyncValidatorFn | null;
name: string | null;
name: string | number | null;
readonly validator: ValidatorFn | null;
valueAccessor: ControlValueAccessor | null;
abstract viewToModelUpdate(newValue: any): void;
Expand Down

0 comments on commit 628b0c1

Please sign in to comment.