28 Commits

Author SHA1 Message Date
Andrew Kushnir
1bc53eb303 fix(forms): more precise control cleanup (#39623)
Currently when an instance of the `FormControlName` directive is destroyed, the Forms package invokes
the `cleanUpControl` to clear all directive-specific logic (such as validators, onChange handlers,
etc) from a bound control. The logic of the `cleanUpControl` function should revert all setup
performed by the `setUpControl` function. However the `cleanUpControl` is too aggressive and removes
all callbacks related to the onChange and disabled state handling. This is causing problems when
a form control is bound to multiple FormControlName` directives, causing other instances of that
directive to stop working correctly when the first one is destroyed.

This commit updates the cleanup logic to only remove callbacks added while setting up a control
for a given directive instance.

The fix is needed to allow adding `cleanUpControl` function to other places where cleanup is needed
(missing this function calls in some other places causes memory leak issues).

PR Close #39623
2020-11-12 09:38:19 -08:00
Andrew Kushnir
e96b379385 fix(forms): remove validators while cleaning up a control (#39234)
Prior to this commit, the `cleanUpControl` function (responsible for cleaning up control instance)
was not taking validators into account. As a result, these validators remain registered on a detached
form control instance, thus causing memory leaks. This commit updates the `cleanUpControl` function
logic to also run validators cleanup.

As a part of this change, the logic to setup and cleanup validators was refactored and moved to
separate functions (with completely opposite behavior), so that they can be reused in the future.

This commit doesn't add the `cleanUpControl` calls to all possible places, it just fixes the cases
where this function is being called, but doesn't fully perform a cleanup. The `cleanUpControl`
function calls will be added to other parts of code (to avoid more memory leaks) in a followup PR.

PR Close #39234
2020-11-04 10:58:24 -08:00
Andrew Kushnir
0723331b2a refactor(forms): move common validators-related logic to the AbstractControlDirective class (#38280)
This commit refactors validators-related logic that is common across most of the directives.

A couple notes on this refactoring:
* common logic was moved to the `AbstractControlDirective` class (including `validator` and
`asyncValidator` getters)
* sync/async validators are now composed in `AbstractControlDirective` class eagerly when validators
are set with `_setValidators` and `_setAsyncValidators` calls and the result is stored in directive
instance (thus getters return cached versions of validator fn). This is needed to make sure composed
validator function remains the same (retains its identity) for a given directive instance, so that
this function can be added and later removed from an instance of an AbstractControl-based class
(like `FormControl`). Preserving validator function is required to perform proper cleanup (in followup
PRs) of the AbstractControl-based classes when a directive is destroyed.

PR Close #38280
2020-10-28 09:48:20 -07:00
Sonu Kapoor
201a546af8 perf(forms): use internal ngDevMode flag to tree-shake error messages in prod builds (#37821)
This commit adds a guard before throwing any forms errors. This will tree-shake
error messages which cannot be minified. It should also help to reduce the
bundle size of the `forms` package in production by ~20%.

Closes #37697

PR Close #37821
2020-08-24 09:26:28 -07:00
Andrew Kushnir
856db56cca refactor(forms): get rid of duplicate functions (#38371)
This commit performs minor refactoring in Forms package to get rid of duplicate functions.
It looks like the functions were duplicated due to a slightly different type signatures, but
their logic is completely identical. The logic in retained functions remains the same and now
these function also accept a generic type to achieve the same level of type safety.

PR Close #38371
2020-08-07 11:40:04 -07:00
Andrew Scott
4456e7e4de refactor(core): remove looseIdentical in favor of built-in Object.is (#37191)
Remove `looseIdentical` implementation and instead use the ES2015 `Object.is` in its place.
They behave exactly the same way except for `+0`/`-0`.
`looseIdentical(+0, -0)` => `true`
`Object.is(+0, -0)` => `false`

Other than the difference noted above, this is not be a breaking change because:
1. `looseIdentical` is a private API
2. ES2015 is listed as a mandatory polyfill in the [browser support
guide](https://angular.io/guide/browser-support#mandatory-polyfills)
3. Also note that `Ivy` already uses `Object.is` in `bindingUpdated`.

PR Close #37191
2020-06-01 17:19:17 -04:00
Joey Perrott
d1ea1f4c7f build: update license headers to reference Google LLC (#37205)
Update the license headers throughout the repository to reference Google LLC
rather than Google Inc, for the required license headers.

PR Close #37205
2020-05-26 14:26:58 -04:00
Andrew Kushnir
7d0af179e3 style(forms): reformat of the forms package after clang update (#36466)
PR Close #36466
2020-04-07 09:47:09 -07:00
cexbrayat
628b0c1154 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
2019-08-13 14:21:25 -07:00
Kara Erickson
9a37e827e2 Revert "feat(forms): formControlName also accepts a number (#30606)" (#32088)
This reverts commit a6472984122a73c2c9016746374ef383c6cb52c4.

PR Close #32088
2019-08-09 17:29:27 -07:00
cexbrayat
a647298412 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
2019-08-09 10:39:22 -07:00
Paul Gschwendtner
221cbd0b47 refactor(forms): ensure compatibility with typescript strict flag (#30993)
As part of FW-1265, the `@angular/forms` package is made compatible
with the TypeScript `--strict` flag. Read more about the strict flag [here](https://www.typescriptlang.org/docs/handbook/compiler-options.html)

PR Close #30993
2019-07-18 14:21:26 -07:00
Dirk Luijk
23cc3ef2eb fix(forms): improve error message for invalid value accessors (#22731)
Signed-off-by: Dirk Luijk <mail@dirkluijk.nl>

PR Close #22731
2018-04-04 08:20:55 -07:00
Kara Erickson
8fb34bcd43 refactor(forms): deprecate ngModel usage on same field as formControl (#22633)
Support for using the `ngModel` input property and `ngModelChange`
event with reactive form directives has been deprecated in
Angular v6 and will be removed in Angular v7.

Now deprecated:
```html
<input [formControl]="control" [(ngModel)]="value">
```

```ts
this.value = 'some value';
```

This has been deprecated for a few reasons. First, developers have
found this pattern confusing. It seems like the actual `ngModel`
directive is being used, but in fact it's an input/output property
named `ngModel` on the reactive form directive that simply approximates
(some of) its behavior. Specifically, it allows getting/setting the
value and intercepting value events. However, some of `ngModel`'s other
features - like delaying updates with`ngModelOptions` or exporting the
directive - simply don't work, which has understandably caused some
confusion.

In addition, this pattern mixes template-driven and reactive forms
strategies, which we generally don't recommend because it doesn't take
advantage of the full benefits of either strategy. Setting the value in
the template violates the template-agnostic principles behind reactive
forms, whereas adding a FormControl/FormGroup layer in the class removes
the convenience of defining forms in the template.

To update your code before v7, you'll want to decide whether to stick
with reactive form directives (and get/set values using reactive forms
patterns) or switch over to template-driven directives.

After (choice 1 - use reactive forms):

```html
<input [formControl]="control">
```

```ts
this.control.setValue('some value');
```

After (choice 2 - use template-driven forms):

```html
<input [(ngModel)]="value">
```

```ts
this.value = 'some value';
```

You can also choose to silence this warning by providing a config for
`ReactiveFormsModule` at import time:

```ts
imports: [
  ReactiveFormsModule.withConfig({warnOnNgModelWithFormControl: 'never'});
]
```

Alternatively, you can choose to surface a separate warning for each
instance of this pattern with a config value of `"always"`. This may
help to track down where in the code the pattern is being used as the
code is being updated.

Note: `warnOnNgModelWithFormControl` is set up as deprecated so that it
can be removed in v7 when it is no longer needed. This will not display
properly in API docs yet because dgeni doesn't yet support deprecating
properties in object literals, but we have an open issue to resolve the
discrepancy here: https://github.com/angular/angular/issues/22640.

PR Close #22633
2018-03-07 20:47:53 -08:00
Philip Pham
3e6a86fb0a fix(forms): set state before emitting a value from ngModelChange (#21514)
Closes #21513.

PR Close #21514
2018-02-21 15:59:33 -08:00
Miško Hevery
cf8d512e43 Revert "fix(forms): set state before emitting a value from ngModelChange (#21514)"
This reverts commit 9744a1c966808f152559721215b9b0735308186a.
2018-02-09 10:11:23 -08:00
Philip Pham
9744a1c966 fix(forms): set state before emitting a value from ngModelChange (#21514)
Closes #21513.

PR Close #21514
2018-02-07 12:05:43 -08:00
Kara Erickson
69c53c3e03 fix(forms): updateOn should check if change occurred (#20358)
Fixes #20259.

PR Close #20358
2017-11-17 16:28:46 -06:00
Kara Erickson
1cfa79ca4e feat(forms): add updateOn support to ngModelOptions
This commit introduces a new option to template-driven forms that
improves performance by delaying form control updates until the
"blur" or "submit" event.  To use it, set the `updateOn` property
in `ngModelOptions`.

```html
<input ngModel [ngModelOptions]="{updateOn: blur}">
```

Like in AngularJS, setting `updateOn` to `blur` or `submit` will
delay the update of the value as well as the validation status.
Updating value and validity together keeps the system easy to reason
about, as the two will always be in sync.  It's also worth noting
that the value/validation pipeline does still run when the form is
initialized (in order to support initial values).

Upcoming PRs will address:

* Support for setting group-level `updateOn` in template-driven forms
* Option for skipping initial validation run or more global error
display configuration
* Better support of reactive validation strategies

See more context in #18408, #18514, and the [design doc](https://docs.google.com/document/d/1dlJjRXYeuHRygryK0XoFrZNqW86jH4wobftCFyYa1PA/edit#heading=h.r6gn0i8f19wz).
2017-08-15 16:28:52 -07:00
Kara
ff5c58be6b feat(forms): add default updateOn values for groups and arrays (#18536)
This commit adds support for setting default `updateOn` values
in `FormGroups` and `FormArrays`. If you set `updateOn` to
’blur’` at the group level, all child controls will default to `’blur’`,
unless the child has explicitly specified a different `updateOn` value.

```
const c = new FormGroup({
   one: new FormControl()
}, {updateOn: blur});
```

 It's worth noting that parent groups will always update their value and
validity immediately upon value/validity updates from children. In other
words, if a group is set to update on blur and its children are individually
set to update on change, the group will still update on change with its
children; its default value will simply not be used.
2017-08-09 15:41:53 -07:00
Kara
f69561b2de feat(forms): add updateOn submit option to FormControls (#18514) 2017-08-07 15:39:25 -07:00
Kara
333a708bb6 feat(forms): add updateOn blur option to FormControls (#18408)
By default, the value and validation status of a `FormControl` updates
whenever its value changes. If an application has heavy validation
requirements, updating on every text change can sometimes be too expensive.

This commit introduces a new option that improves performance by delaying
form control updates until the "blur" event.  To use it, set the `updateOn`
option to `blur` when instantiating the `FormControl`.

```ts
// example without validators
const c = new FormControl(, { updateOn: blur });

// example with validators
const c= new FormControl(, {
   validators: Validators.required,
   updateOn: blur
});
```

Like in AngularJS, setting `updateOn` to `blur` will delay the update of
the value as well as the validation status. Updating value and validity
together keeps the system easy to reason about, as the two will always be
in sync. It's  also worth noting that the value/validation pipeline does
still run when the form is initialized (in order to support initial values).

Closes #7113
2017-08-02 18:10:10 -07:00
Miško Hevery
57bc245cb4 fix(forms): Update types for TypeScript nullability support
This reverts commit 6d930d2fc5069018de2abd532bf601414bdbbd10.
2017-04-18 12:07:33 -07:00
Tobias Bosch
6d930d2fc5 Revert "fix(forms): Update types for TypeScript nullability support"
This reverts commit 6649743a2d18bb7a57c25a2e35bf44d2e0d86868.

Broke in G3.
2017-04-17 09:56:09 -07:00
Miško Hevery
6649743a2d fix(forms): Update types for TypeScript nullability support
This reverts commit 2e47a0d19fa1d1527cf998d87cd8a49bc968606a.
2017-04-14 15:10:26 -07:00
Tobias Bosch
2e47a0d19f Revert "fix(forms): Update types for TypeScript nullability support (#15859)" (#15977)
This reverts commit 6a2e08d0a8ae24b73d457d58d1b224ce1487ffac.
2017-04-13 18:03:42 -07:00
Miško Hevery
6a2e08d0a8 fix(forms): Update types for TypeScript nullability support (#15859) 2017-04-13 17:14:08 -07:00
Jason Aden
3e51a19983 refactor: move angular source to /packages rather than modules/@angular 2017-03-08 16:29:27 -08:00