When a FormControl, FormArray, or FormGroup is first constructed, if an async validator is attached, the `statusChanges` observable should receive a message when the validator complete (i.e. pending -> valid/invalid). If the validator was provided as part of the constructor options, it was not fired at construction time, which is fixed in this PR.
Fixes#35309.
PR Close#42553
As previously discussed in pull/31070 and issues/30486, this would be useful because it is often desirable to apply styles to fields that are both `ng-invalid` and `ng-pristine` after the first attempt at form submission, but Angular does not provide any simple way to do this (although evidently Angularjs did). This will now be possible with a descendant selector such as `.ng-submitted .ng-invalid`.
In this implementation, the directive that sets control status classes on forms and formGroups has its set of statuses widened to include `ng-submitted`. Then, in the event that `is('submitted')` is invoked, the `submitted` property of the control container is returned iff it exists. This is preferred over checking whether the container is a `Form` or `FormGroup` directly to avoid reflecting on those classes.
Closes#30486.
PR Close#42132.
This reverts commit 00b1444d12, undoing the rollback of this change.
PR Close#42132
For quite a while it is an unspoken convention to add a trailing
new-line files within the Angular repository. This was never enforced
automatically, but has been frequently raised in pull requests through
manual review. This commit sets up a lint rule so that this is
"officially" enforced and doesn't require manual review.
PR Close#42478
Switches the repository to TypeScript 4.3 and the latest
version of tslib. This involves updating the peer dependency
ranges on `typescript` for the compiler CLI and for the Bazel
package. Tests for new TypeScript features have been added to
ensure compatibility with Angular's ngtsc compiler.
PR Close#42022
As previously discussed in pull/31070 and issues/30486, this would be useful because it is often desirable to apply styles to fields that are both `ng-invalid` and `ng-pristine` after the first attempt at form submission, but Angular does not provide any simple way to do this (although evidently Angularjs did). This will now be possible with a descendant selector such as `.ng-submitted .ng-invalid`.
In this implementation, the directive that sets control status classes on forms and formGroups has its set of statuses widened to include `ng-submitted`. Then, in the event that `is('submitted')` is invoked, the `submitted` property of the control container is returned iff it exists. This is preferred over checking whether the container is a `Form` or `FormGroup` directly to avoid reflecting on those classes.
Closes#30486.
PR Close#42132
Prior to this change the `min` and `max` validator directives would not
set the `min` and `max` attributes on the host element. The problem was
caused by the truthy check in host binding expression that was
calculated as `false` when `0` is used as a value. This commit updates
the logic to leverage nullish coalescing operator in these host binding
expressions, so `0` is treated as a valid value, thus the `min` and
`max` attributes are set correctly.
Partially closes#42267
PR Close#42412
We have some internal proxies for all of the Jasmine functions, as well as some other helpers. This code hasn't been touched in more than 5 years, it can lead to confusion and it isn't really necessary since the same can be achieved using Jasmine.
These changes remove most of the code and clean up our existing unit tests.
PR Close#42177
Update the supported range of node versions for to be less restrictive, no longer causing
yarn or npm to fail engine's checks for future versions of node.
While this change will no longer cause yarn or npm to fail these engine's check, this does
not reflect a change in the officially supported versions of node for Angular. Angular
continues to maintain support for Active LTS and Maintenance LTS versions of node.
PR Close#42205
Remove publishConfig property from the package.json entry for each of the entries in
the publish configuration. Using the wombat proxy is now ensured/managed by the
ng-dev release tooling.
PR Close#42104
The Validator and AsyncValidator interfaces provide a callback, `registerOnValidatorChange(fn)`. `registerOnValidatorChange` is supposed to be fired at least once to register `fn` with the validator. `fn` is then called by the validator whenever its inputs change. This was previously not happening for FormGroup validators, and is now fixed.
PR Close#41971
This commit adds a base class that contains common logic for all ControlValueAccessors defined in Forms package. This allows to remove duplicated logic from all built-in ControlValueAccessor classes.
PR Close#41225
This commit makes the `RadioControlRegistry` class tree-shakable by adding the `providedIn` property to its
`@Injectable` decorator. Now if the radio buttons are not used in the app (thus no `RadioControlValueAccessor`
directive is initialized), the `RadioControlRegistry` should not be included into application's prod bundle.
PR Close#41126
This commit makes the `FormBuilder` class tree-shakable by adding the `providedIn` property to its `@Injectable`
decorator. Now if the `FormBuilder` class is not referenced in application's code, it should not be included into
its production bundle.
PR Close#41126
Currently the `Validators` class contains a number of static methods that represent different validators as well as some helper methods. Since class methods are not tree-shakable, any reference to the `Validator` class retains all of its methods (even if you've used just one).
This commit refactors the code to extract the logic into standalone functions and use these functions in the code instead of referencing them via `Validators` class. That should make the code more tree-shakable. The `Validators` class still retains its structure and calls these standalone methods internally to keep this change backwards-compatible.
PR Close#41189
This commit updates Forms code to avoid direct references to all built-in ControlValueAccessor classes, which
prevents their tree-shaking from production builds. Instead, a new static property is added to all built-in
ControlValueAccessors, which is checked when we need to identify whether a given ControlValueAccessors is a
built-in one.
PR Close#41146
Currently the code in the `FormGroupDirective` assumes that the shape of the underlying `FormGroup` never
changes and `FormControl`s are not replaced with other types. In practice this is possible and Forms code
should be able to process such changes in FormGroup shape.
This commit adds extra check to the `FormGroupDirective` class to avoid applying FormControl-specific to
other types.
Fixes#13788.
PR Close#40829
This commit adds the `emitEvent` option to the following FormArray and FormGroup methods:
* FormGroup.addControl
* FormGroup.removeControl
* FormGroup.setControl
* FormArray.push
* FormArray.insert
* FormArray.removeAt
* FormArray.setControl
* FormArray.clear
This option can be used to prevent an event from being emitted when adding or removing controls.
BREAKING CHANGE:
The `emitEvent` option was added to the following `FormArray` and `FormGroup` methods:
* FormGroup.addControl
* FormGroup.removeControl
* FormGroup.setControl
* FormArray.push
* FormArray.insert
* FormArray.removeAt
* FormArray.setControl
* FormArray.clear
If your app has custom classes that extend `FormArray` or `FormGroup` classes and override the
above-mentioned methods, you may need to update your implementation to take the new options into
account and make sure that overrides are compatible from a types perspective.
Closes#29662.
PR Close#31031
This commit adds the missing `min` and `max` validators.
BREAKING CHANGE:
Previously `min` and `max` attributes defined on the `<input type="number">`
were ignored by Forms module. Now presence of these attributes would
trigger min/max validation logic (in case `formControl`, `formControlName`
or `ngModel` directives are also present on a given input) and
corresponding form control status would reflect that.
Fixes#16352
PR Close#39063
This commit updates `AbstractControlStatus` directive code to remove duplicated logic in getters and replaces
that logic with a new function that accepts an argument.
PR Close#40651
Prior to this commit, the `patchValue()` of the `FormGroup` and `FormArray` classes used to throw an exception
when the `value` argument contained a data structure that has `null` or `undefined` as a value for a field
that represents an instance of `FormGroup` or `FormArray` (for `FormControl` it's not a problem, since it
doesn't have nested controls), since the `patchValue()` method tried to iterate over provided values to
match current data structure.
This commit updates the `patchValue()` logic in `FormGroup` and `FormArray` classes to just ignore `null` and
`undefined` values (without any changes to corresponding `FormGroup` and `FormArray` instances). This
behavior looks inline with the `patchValue()` method goal of "doing its best to match the values to the
correct controls" (quote from docs).
Fixes#36672.
Fixes#21021.
PR Close#40534
PR #39235 introduced additional cleanup logic for form controls and directives. The cleanup logic relies
on the presence of ControlValueAccessor instances on FormControlName and FormControl directives. In general
these fields are present and there are also checks to make sure that the mentioned directive instances are
created with CVAs. However some scenarios (primarily tests) may invoke the logic in a way that the directive
instance would not be fully initialized, thus causing CVA to be absent. As a result, the cleanup logic fails
while trying to call some methods on associated CVA instances.
This commit updates the cleanup logic to take into account the situation when CVA is not present.
Fixes#40521.
PR Close#40526
When a form is reset, it goes through `_forEachChild` to call `reset` on each of its children.
The problem is that if a control is removed while the loop is running (e.g. by a subscription),
the form will throw an error, because it built up the list of available control before the loop
started.
These changes fix the issue by adding a null check before invoing the callback.
Fixes#33401.
PR Close#40462
The `NgControlStatusGroup` directive is shared between template-driven and reactive form modules. In cases when
only reactive forms module is present, the `NgControlStatusGroup` directive is still activated on all `<form>`
elements, but if there is no other reactive directive applied (such as `formGroup`), corresponding `ControlContainer`
token is missing, thus causing exceptions (since `NgControlStatusGroup` directive relies on it to determine the
status). This commit updates the logic to handle the case when no `ControlContainer` is present (effectively making
directive logic a noop in this case).
Alternative approach (more risky) worth considering in the future is to split the `NgControlStatusGroup` into
2 directives with different set of selectors and include them into template-driven and reactive modules separately.
The downside is that these directives might be activated simultaneously on the same element (e.g. `<form>`),
effectively doing the work twice.
Resolves#38391.
PR Close#40344
Prior to this commit, removing `FormControlDirective` and `FormGroupName` directive instances didn't clear
the callbacks previously registered on FromControl/FormGroup class instances. As a result, these callbacks
were executed even after `FormControlDirective` and `FormGroupName` directive instances were destroyed. That was
also causing memory leaks since these callbacks also retained references to DOM elements.
This commit updates the cleanup logic to take care of properly detaching FormControl/FormGroup/FormArray instances
from the view by removing view-specific callback at destroy time.
Closes#20007, #37431, #39590.
PR Close#39235
This commit adds `ngDevMode` guard to call `_ngModelWarning` only
in dev mode (similar to how things work in other parts of Ivy runtime code).
The `ngDevMode` flag helps to tree-shake this function from production builds
(since it will act as no-op, in dev mode everything will work as it works right now)
to decrease production bundle size.
PR Close#39964
This expands the deprecation message that started to pop up in v11.0.3
after the landing of commit e148382bd0,
that deprecated the `{[key: string]: any}` type for the options property of the `FormBuilder.group` method.
It turns out that having a custom validator declared as
`{ validators: (group: FormGroup) => ValidationErrors|null }` works in practice,
but is now inferred by TS as the deprecated version of `group`
(because `FormGroup` is a subclass of `AbstractControl` that `ValidatorFn` expects).
We considered the possibility of tweaking the forms API to accept such validators,
but it turns out to generate too many changes in the framework or possible breaking changes for Angular users.
We settled for a more explicit deprecation message, elaborated with the help of @petebacondarwin.
This will hopefully help developers to understand why the deprecation warning is showing up
when they think they are already using the non-deprecated overload.
PR Close#39946
DEPRECATION:
Mark the {[key: string]: any} type for the options property of the FormBuilder.group method as deprecated.
Using AbstractControlOptions gives the same functionality and is type-safe.
PR Close#39769
The value of a `FormControl` is treated in a special way (called boxed values) when it's an object with exactly
2 fields: `value` and `disabled`. This commit adds a test which verifies that an object is not treated as a boxed
value when `disabled` field is present, but `value` is missing.
PR Close#39801
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
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
This commit improves the ngModel docs, specifically:
- clarifies purpose of the name attribute in ngModelOptions
- clarifies on the interaction with a parent form or lack thereof
- fix inconsistency with analogy for two-way binding
- cleans up some typos and extra wordiness
- clarifies language around common properties
- adds missing preposition to commit message format origins
PR Close#39481
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
Due to how the global and sticky flag make RegExp objects stateful,
adds section detailing how it is not recommended
to use these flags for control validations.
PR Close#39055
This commit improves the DefaultValueAccessor directive docs by:
- adding the `ngDefaultControl` as a search keyword to the description
- adding an example of the `ngDefaultControl` usage
Closes#35375.
PR Close#39404
Prior to this change, the `validators` and `asyncValidators` fields of a few Forms directives
were typed as `any[]`. This commit updates the types and makes them consistent for all directives
in the Forms package.
BREAKING CHANGE:
Directives in the `@angular/forms` package used to have `any[]` as a type of `validators` and
`asyncValidators` arguments in constructors. Now these arguments are properly typed, so if your
code relies on directive constructor types it may require some updates to improve type safety.
PR Close#38944