This commit deprecates the aliases for the control events to ease the changes in G3
A follow-up commit will remove those deprecated entries.
PR Close#55698
Since we aren't using clang anymore, we can remove the comments and the workarounds that were in place to prevent it from doing the wrong thing.
PR Close#55750
When a formControlName is used without a parent formGroup, an error is
logged in the console. Before this commit, there was no information
about which control had the issue. Now, it's reported and the
troubleshoot is much faster.
PR Close#55397
This commit introduces a new method to subscribe to on every `AbstractControl` subclass.
It allows to track value, pristine, touched and status changes on a given control.
Fixes#10887
PR Close#54579
This change aligns the stability of `ComponentFixture` with that of
`ApplicationRef`, preventing confusing differences between the two as
more APIs start using the `PendingTasks` that may not be tracked by
`NgZone`.
BREAKING CHANGE: `ComponentFixture.whenStable` now matches the
`ApplicationRef.isStable` observable. Prior to this change, stability
of the fixture did not include everything that was considered in
`ApplicationRef`. `whenStable` of the fixture will now include unfinished
router navigations and unfinished `HttpClient` requests. This will cause
tests that `await` the `whenStable` promise to time out when there are
incomplete requests. To fix this, remove the `whenStable`,
instead wait for another condition, or ensure `HttpTestingController`
mocks responses for all requests. Try adding `HttpTestingController.verify()`
before your `await fixture.whenStable` to identify the open requests.
Also, make sure your tests wait for the stability promise. We found many
examples of tests that did not, meaning the expectations did not execute
within the test body.
In addition, `ComponentFixture.isStable` would synchronously switch to
true in some scenarios but will now always be asynchronous.
PR Close#54949
The `RadioControlRegistry` was only provided in a module, providedIn: 'root' fixes that issue.
Fixes#54117
Co-authored-by: sr5434 <118690585+sr5434@users.noreply.github.com>
PR Close#54130
A lot of our tests are wrapped in `{}` which serves no purpose, aside from increasing the nesting level and, in some cases, causing confusion. The braces appear to be a leftover from a time when all tests were wrapped in a `function main() {}`. The function declaration was removed in #21053, but the braces remained, presumably because it was easier to search&replace for `function main()`, but not to remove the braces at the same time.
PR Close#52239
This adds `generate_api_docs` targets to all of the packages for which we publish api reference docs. One known issue here is that any type information that comes from another package (e.g. router depending on core) currently resolve to `any` because the other sources are not available in the program. This can be tackled in a follow-up commit.
This commit also updates the install patch for `@angular/build-tools` to use the local version of compiler-cli.
PR Close#52034
Non typed forms allow to pass null to nested groups when calling `formGroup.reset()`, this commit prevent an undefined access.
fixes#20509
PR Close#48830
The `Writable` type is usefull when we want overwrite readonly properties and we still want to maintain code navigation/reference. It should be use instead of `any` type assertions for example.
PR Close#49754
BREAKING CHANGE: Node.js v16 support has been removed and the minimum support version has been bumped to 18.13.0.
Node.js v16 is planned to be End-of-Life on 2023-09-11. Angular will stop supporting Node.js v16 in Angular v17. For Node.js release schedule details, please see: https://github.com/nodejs/release#release-schedule
PR Close#51755
Currently internally Angular has some customized tsconfig files, because we don't align with the tsconfig of the rest of g3. These changes enable `noImplicitReturns` and `noPropertyAccessFromIndexSignature` to align better with the internal config.
PR Close#51728
We enabled a lint rule internally to require that multi-provided
`InjectionToken`s have a `readonly` array type, the tokens in this
PR do not follow this rule and are causing lint violations.
Fixes#51124
PR Close#51125
According to the HTML specification most attributes are defined as strings, however some can be interpreted as different types like booleans or numbers. [In the HTML standard](https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#boolean-attributes), boolean attributes are considered `true` if they are present on a DOM node and `false` if they are omitted. Common examples of boolean attributes are `disabled` on interactive elements like `<button>` or `checked` on `<input type="checkbox">`. Another example of an attribute that is defined as a string, but interpreted as a different type is the `value` attribute of `<input type="number">` which logs a warning and ignores the value if it can't be parsed as a number.
Historically, authoring Angular inputs that match the native behavior in a type-safe way has been difficult for developers, because Angular interprets all static attributes as strings. While some recent TypeScript versions made this easier by allowing setters and getters to have different types, supporting this pattern still requires a lot of boilerplate and additional properties to be declared. For example, currently developers have to write something like this to have a `disabled` input that behaves like the native one:
```typescript
import {Directive, Input} from '@angular/core';
@Directive({selector: 'mat-checkbox'})
export class MatCheckbox {
@Input()
get disabled() {
return this._disabled;
}
set disabled(value: any) {
this._disabled = typeof value === 'boolean' ? value : (value != null && value !== 'false');
}
private _disabled = false;
}
```
This feature aims to address the issue by introducing a `transform` property on inputs. If an input has a `transform` function, any values set through the template will be passed through the function before being assigned to the directive instance. The example from above can be rewritten to the following:
```typescript
import {Directive, Input, booleanAttribute} from '@angular/core';
@Directive({selector: 'mat-checkbox'})
export class MatCheckbox {
@Input({transform: booleanAttribute}) disabled: boolean = false;
}
```
These changes also add the `booleanAttribute` and `numberAttribute` utilities to `@angular/core` since they're common enough to be useful for most projects.
Fixes#8968.
Fixes#14761.
PR Close#50420
This commit updates the minimum supported Node version across packages from 16.13.0 -> 16.14.0 to ensure compatibility with dependencies.
PR Close#49771
Previously, this PR cleaned up a bug introduced by #48679. However, since that PR needed to be rolled back, this PR now just checks in the test, to prevent that issue from re-occurring in the future.
PR Close#49693
This commit updates parts of the FW to be ES2022 complaint.
These changes are needed to fix the following problems problems with using properties before they are initialized.
Example
```ts
class Foo {
bar = this.buz;
constructor(private buz: unknown){}
}
```
PR Close#49559
This commit updates parts of the FW to be ES2022 complaint.
These changes are needed to fix the following problems problems with using properties before they are initialized.
Example
```ts
class Foo {
bar = this.buz;
constructor(private buz: unknown){}
}
```
PR Close#49332
The private util `isObservable` was actually just testing the same thing as`isSubscribable()`. As the implementation is closer to the function's name, let's only keep ``isSubscribable`.
PR Close#49295
BREAKING CHANGE: Node.js v14 support has been removed
Node.js v14 is planned to be End-of-Life on 2023-04-30. Angular will stop supporting Node.js v14 in Angular v16. Angular v16 will continue to officially support Node.js versions v16 and v18.
PR Close#49255
`setDisabledState` is supposed to be called whenever the disabled state of a control changes, including upon control creation. However, a longstanding bug caused the method to not fire when an *enabled* control was attached. This bug was fixed in v15.
This had a side effect: previously, it was possible to instantiate a reactive form control with `[attr.disabled]=true`, even though the the corresponding control was enabled in the model. (Note that the similar-looking property binding version `[disabled]=true` was always rejected, though.) This resulted in a mismatch between the model and the DOM. Now, because `setDisabledState` is always called, the value in the DOM will be immediately overwritten with the "correct" enabled value.
Users should instead disable the control directly in their model. (There are many ways to do this, such as using the `{value: 'foo', disabled: true}` constructor format, or immediately calling `FooControl.disable()` in `ngOnInit`.)
If this incompatibility is too breaking, you may also opt out using `FormsModule.withConfig` or `ReactiveFormsModule.withConfig` at the time you import it, via the `callSetDisabledState` option.
However, there is an exceptional case: radio buttons. Because Reactive Forms models the entire group of radio buttons as a single `FormControl`, there is no way to control the disabled state for individual radios, so they can no longer be configured as disabled.
In this PR, we have special cased radio buttons to ignore their first call to `setDisabledState` when in `callSetDisabledState: 'always'` mode. This preserves the old behavior.
PR Close#48864
Jasmine has deprecated the `expectationFailOutput` argument and replaced it by the `withContext()` method
Also removing all references to #24571 from the forms unit tests as the non null assertions are fine in the context.
PR Close#48894
Tests now always run with ESM 2020, while previously they ran with
ES2015 CommonJS UMD bundles.
Since ZoneJS does not support intercepting native `async/await` syntax,
the forms test needs to use the zone-compatible variant of
`jasmine_node_tests`. This variant downlevels the native `async/await`
syntax to generators that ZoneJS can intercept. All of this is done
using the dev-infra ESBuild `spec_bundle` rule.
PR Close#48521
Since we generate a `.mjs` file as entry-point for jasmine tests,
a couple of issues prevented the transitive dependencies from
bootstrap targets to be brought in (causing resolution errors):
1. The `_files` (previously `_esm2015`) targets are no longer needed,
and they also miss all the information on runfiles.
2. The aspect for computing linker mappings does not respect the
`bootstrap` attribute from the `spec_entrypoint` so we manually
add the extract ESM output targets (this rule works with the aspect
and forwards linker mappings).
PR Close#48521
For every `ts_library` target we expose a shorthand that grants
access to the JS files because `DefaultInfo` of a ts library
only exposes the `.d.ts` files.
We rename this away from `es2015` since in practice it's a much
higher target these days. Additionally we no longer use the devmode
output but rather use the prodmode output which has the explicit
`.mjs` output- compatible with ESM.
PR Close#48521
refactor(forms): make FormBuilder classes provided in root
This commit updates the FormBuilder classes to provide them in root
instead of using a deprecated pattern of providing a service in a specific
module using the `providedIn` syntax.
Closes#48237.
PR Close#48245
Fixes that the `AbstractControl` was mutating the validators arrays being passed into the constructor an helper methods like `setValidators`.
Fixes#47827.
PR Close#47830
[A Github issue](https://github.com/angular/angular/issues/43821) about an arcane-sounding Forms error is one of the repo's top-ten most visited pages. This converts the error to `RuntimeErrorCode` and adds a dedicated guide to explain how to solve it.
PR Close#47969
Fixes that the `AbstractControl` was mutating the validators arrays being passed into the constructor an helper methods like `setValidators`.
Fixes#47827.
PR Close#47830
This change aligns with the supported Node.js versions of the Angular CLI.
See: https://github.com/angular/angular-cli/pull/24026
BREAKING CHANGE: Angular no longer supports Node.js versions `14.[15-19].x` and `16.[10-12].x`. Current supported versions of Node.js are `14.20.x`, `16.13.x` and `18.10.x`.
PR Close#47730
Previously, `setDisabledState` was never called when attached if the control is enabled. This PR fixes the bug, and creates a configuration option to opt-out of the fix.
Fixes#35309.
BREAKING CHANGE: setDisabledState will always be called when a `ControlValueAccessor` is attached. You can opt-out with `FormsModule.withConfig` or `ReactiveFormsModule.withConfig`.
PR Close#47576
This commit exports existing utility functions to check for control instances:
isFormControl, isFormGroup, isFormRecord, isFormArray
Those are useful when implementing validators that use the specifics of one of those control types.
To narrow down the type to what it actually is, we can now use the util functions in validators:
```
export const myArrayValidator: ValidatorFn = (control) => {
if (!isFormArray(control)) { return null; }
// now you can use FormArray-specific members, e.g.:
if (control.controls.every(c => !!c.value) {
return { myerror: true }
} else { return null; }
}
```
PR Close#47718
Updated methods' description verbs. They are sometimes used with the assumption of the 'it' pronoun and sometimes not. For instance, the verb 'to construct' is used with 's' in one method description and not others. It is the case for other verbs as well. This is also remarkable in the description of the built-in methods of FormArray.
PR Close#47399
The forms `submit` event handlers have a `return false` to prevent form submissions from reloading the page, however this also prevents the browser behavior for forms with `method="dialog"`.
These changes add an exception since the `method="dialog"` doesn't refresh the page.
Fixes#47150.
PR Close#47308
Type inference in cases involving `ControlConfig` was previously not working as desired. This was because the compiler was enforcing that `ControlConfig` is a *tuple* -- which is not always that easy to prove! By relaxing this constraint a bit, and just inferring from `ControlConfig` as an array, the type inference catches many more cases, and is generally more correct.
PR Close#47034
Users using the "disabled" property binding on reactive form controls would want to know how to dynamically update the disabled state of a form control when they get a console warning.
PR Close#47041
The new `FormRecord` entity introduced in Angular v14 does not have its builder method.
This commit adds it, allowing to write:
```
const fb = new FormBuilder();
fb.record({ a: 'one' });
```
This works for both the `FormBuilder` and the `NonNullableFormBuilder`
PR Close#46485
Replace `new Error()` in a forms Validators function with `RuntimeError`, for better tree-shakability. Also, improve the error messages, and add documentation.
PR Close#46537
Consider the case in which `FormBuilder` is used to construct a group with an optional field:
```
const controls = { name: fb.control('') };
const foo: FormGroup<{
name: FormControl<string | null>;
address?: FormControl<string | null>;
}> = fb.group<{
name: FormControl<string | null>;
address?: FormControl<string | null>;
}>(controls);
```
Today, with fully strict TypeScript settings, the above will not compile:
```
Types of property 'controls' are incompatible.
Type '{ name: FormControl<string | null>; address?: FormControl<FormGroup<SubFormControls> | null | undefined> | undefined; }' is not assignable to type '{ name: FormControl<string | null>; address?: FormGroup<SubFormControls> | undefined; }'.
```
Notice that the `fb.group(...)` is calculating the following type for address: `address?: FormControl<FormGroup<string|null>`. This is clearly wrong -- an extraneous `FormControl` has been added!
This is coming from the calculation of the result type of `fb.group(...)`. In the type definition, if we cannot detect the outer control type, [we assume it's just an unwrapped value, and automatically wrap it in `FormControl`](https://github.com/angular/angular/blob/14.0.0/packages/forms/src/form_builder.ts#L66).
Because the optional `{address?: FormControl<string|null>}` implicitly makes the RHS have type `FormControl<string|null>|undefined`, [the relevant condition is not satisfied](https://github.com/angular/angular/blob/14.0.0/packages/forms/src/form_builder.ts#L55). In particular, the condition expects just `FormGroup<T>`, not `FormGroup<T>|undefined`. So we assume `T` is a value type, and it gets wrapped with `FormControl`.
The solution is to add the cases where `undefined` is included in the union type when detecting which control `T` is (if any).
PR Close#46253
It is currently unclear which directive to use for FormRecord. This commit amends the docs to explicitly state that the group directives can and should be used with records.
PR Close#46235
DEPRECATED:
It is now deprecated to provide *both* `AbstractControlOption`s and an async validators argument to a FormControl. Previously, the async validators would just be silently dropped, resulting in a probably buggy forms. Now, the constructor call is deprecated, and Angular will print a warning in devmode.
DEPRECATED:
The `initialValueIsDefault` option has been deprecated and replaced with the otherwise-identical `nonNullable` option, for the sake of naming consistency.
In some places, the [@see][1] JSDoc tag was incorrectly used instead of
the [@link][2] inline tag, leading to warnings during doc generation and
the `@see` tags being ignored (and thus shown in the docs as is).
Replace the `@see` tags with the intended `@link` tags.
[1]: https://jsdoc.app/tags-see.html
[2]: https://jsdoc.app/tags-inline-link.html
PR Close#46040
* `FormRecord` jsdocs should now appear on a.io
* The `{@see foo#bar}` syntax previously did not work, and has been replace with backticks
PR Close#46023
Consider a typed group for storing contact information:
```
declare interface ContactControls {
name: FormControl<string|null>;
}
contactForm: FormGroup<ContactControls> = ...;
saveForm(form: FormGroup<ContactControls>) {
service.newContact(contactForm.value);
}
```
What should be the type of `newContact`? The answer, of course, is the value type:
```
declare interface Contact {
name: string|null;
}
class ContactService {
newContact(c: Contact) {}
}
```
This is quite redundant, and therefore, we should allow the value type to be generated automatically. We already have the helper types to do this -- we just need to document and export them. Then, this becomes possible:
```
class ContactService {
newContact(c: RawValue<FormGroup<ContactControls>>) {}
}
```
PR Close#45978
Previously, using `FormBuilder` with a union type would produce unions of *controls*:
```
// `foo` has type `FormControl<string>|FormControl<number>`.
const c = fb.nonNullable.group({foo: 'bar' as string | number});
```
This actually works in many cases, due to how extraordinarily powerful Typescript's distributive types are (e.g. `value` still has type `string|number`), but it is subtly incorrect. Here is a code example that exposes the reason the inference is incorrect. It exploits the fact that Typescript will not "un-distribute" a type, producing an obviously spurious error:
```
// fc gets an inferred distributive union type `FormControl<string> | FormControl<number>`
let fc = c.controls.foo;
// Error: Type 'FormControl<string | number>' is not assignable to type 'FormControl<string> | FormControl<number>'.
fc = new FormControl<string|number>('', {initialValueIsDefault: true});
```
Instead, we want the union to apply to the *values*:
```
// `foo` should have type `FormControl<string|number>`.
const c = fb.nonNullable.group({foo: 'bar' as string | number});
```
Essentially, we want to prevent Typescript from distributing the type. [As specified in the handbook](https://www.typescriptlang.org/docs/handbook/2/conditional-types.html#distributive-conditional-types):
> Typically, distributivity is the desired behavior. To avoid that behavior, you can surround each side of the extends keyword with square brackets.
This PR applies this suggestion to `FormBuilder`'s type inference.
Fixes#45912.
PR Close#45942
Based on early feedback, calling `fb.nonNullable.group(...)` continues to be clunky for a form with many such groups. Allowing `NonNullableFormBuilder` to be directly injected enables the following:
```
constructor(private fb: NonNullableFormBuilder) {}
```
PR Close#45904
With typed forms, all `FormControl`s are nullable by default, because they can be reset to `null`. This behavior is possible to change by passing the option `initialValueIsDefault: true`. However, in a large form, this is extremely cumbersome, as the option must be repeated over and over. Additionally, it is not possible to take full advantage of `FormBuilder`, since `FormBuilder.group` and `FormBuilder.array` will produce nullable controls.
This PR introduces a new accessor `FormBuilder.nonNullable`, which produces *non-nullable* controls. Specifically, any call to `.control` will produce controls with `{initialValueIsDefault: true}`, and calls to `.array` or `.group` that implicitly build inner controls will have the same effect.
```ts
let nfb = new FormBuilder().nonNullable;
let name = nfb.group({who: 'Alex'}); // FormGroup<{who: FormControl<string>}>
name.reset();
console.log(name); // {who: 'Alex'}
```
PR Close#45852
Speeds up the dev-turnaround by only bundling types when packaging. Currently
bundling occurs for all the `ng_module` targets in devmode.
This has various positive benefits:
* Avoidance of this rather slower operation in development
* Makes APF-built packages also handle types for `ts_library` targets consistently.
* Allows us to ensure APF entry-points have `d.ts` _always_ bundled (working with ESM
module resolution in TypeScript -- currently experimental)
* Allows us to remove the secondary `package.json` files from APF (maybe APF v14? - seems
low-impact). This would clean-up the APF even more and fix resolution issues (like in Vite)
PR Close#45405
Previously, the following code would fail to compile:
```
let form: FormGroup<{email: FormControl<string | null>}>;
form = fb.group({
email: ['', Validators.required]
});
```
This is because the compiler was unable to properly infer the inner type of `ControlConfig` arrays in some cases. The same issue applies to `FormArray` as well under certain circumstances.
This change cleans up the `FormBuilder` type signatures to always use the explicit Element type, and to catch `ControlConfig` types that might fall through.
PR Close#45684
As part of the typed forms RFC, we proposed the creation of a new FormRecord type, to support dynamic groups with homogenous values. This PR introduces FormRecord, as a subclass of FormGroup.
PR Close#45607
This PR strongly types the forms package by adding generics to AbstractControl classes as well as FormBuilder. This makes forms type-safe and null-safe, for both controls and values.
The design uses a "control-types" approach. In other words, the type parameter on FormGroup is an object containing controls, and the type parameter on FormArray is an array of controls.
Special thanks to Alex Rickabaugh and Andrew Kushnir for co-design & implementation, to Sonu Kapoor and Netanel Basal for illustrative prior art, and to Cédric Exbrayat for extensive testing and validation.
BREAKING CHANGE: Forms classes accept a generic.
Forms model classes now accept a generic type parameter. Untyped versions of these classes are available to opt-out of the new, stricter behavior.
PR Close#43834
in the validators documentation, the value for the formControl for both required and requiredTrue validators is an empty string. This is OK for required since it gives us an error. But I think if we set the value of formControl responsible for requiredTrue to something other than an empty string (e.g.: 'some value'), it would demonstrate the difference between required and requiredTrue better.
PR Close#45533
in the validators documentation, the value for the formControl for both required and requiredTrue validators is an empty string. This is OK for required since it gives us an error. But I think if we set the value of formControl responsible for requiredTrue to something other than an empty string (e.g.: 'some value'), it would demonstrate the difference between required and requiredTrue better.
PR Close#45533
Fixes a long-standing issue where swapping out the `FormGroup` and calling `disable` immediately afterwards doesn't actually disable the `ControlValueAccessor`.
Fixes#22556.
PR Close#43499
There was a subtle bug involving the opt-out class for FormBuilder, which I discovered during the ongoing migration. The types must be structurally the same, because people pass around FormBuilders, in addition to passing around the controls they produce. This PR ensures FormBuilder and UntypedFormBuilder are assignable to each other.
PR Close#45421
Close#44724
`DebugNode.triggerEventHandler()` should accept the `eventObj` as an
optional parameter. So the user don't have to write code like
```
elem.triggerEventHandler('click', null);
```
PR Close#45279
Node.js v12 will become EOL on 2022-04-30. As a result, Angular CLI v14 will no longer support Node.js v12.
BREAKING CHANGE:
Support for Node.js v12 has been removed as it will become EOL on 2022-04-30. Please use Node.js v14.15 or later.
PR Close#45286
model.ts is currently extremely large. This is the first step in an attempt to refactor it to be more easily navigable and reviewable. This commit breaks up `model.ts` into the following new files:
* `model/abstract_model.ts`: The remainder of the model, including the `AbstractControl` base class and helper functions which are used throughout.
* `model/form_control.ts`: `FormControl`, `FormControlOptions`, and helpers, plus the constructor and untyped friends.
* `model/form_array.ts`: `FormArray` and untyped friends.
* `model/form_group.ts`: `FormGroup` and untyped friends.
This first phase is a purely mechanical code move. There is no new code at all, and no interfaces have been separated.
PR Close#45217
Currently, there is a freestanding `getRawValue` function which examines the type of the control. This is an issue for refactoring `model.ts` because it creates unnecessary dependencies between the `AbstractControl` classes. It is cleaner to simply add this method to the model hierarchy and call it directly, and will ease upcoming refactoring.
PR Close#45200
Currently, there is a freestanding `getRawValue` function which examines the type of the control. This is an issue for refactoring `model.ts` because it creates unnecessary dependencies between the `AbstractControl` classes. It is cleaner to simply add this method to the model hierarchy and call it directly, and will ease upcoming refactoring.
PR Close#45200
We had previously introduced an `AnyForUntypedForms` type alias. However, given our updated migration plan, we actually want to use aliases for the model classes themselves. This commit introduces these aliases, and adds them to the public API. It must be merged before the types, in order to migrate google3.
PR Close#45205
When an `NgModel` is created within a `form`, it receives an `NgControl` based on its `name`, but
the control doesn't get swapped out if the name changes. This can lead to problems if the `NgModel`
is part of an `ngFor`, because the name can change based on its position in the list and a new
control can be defined with the same name, leading us to having multiple directives pointing to
the same control. For example, if we start off with a list like :
```
[0, 1, 2]; -> [NgModel(0), NgModel(1), NgModel(2)]
```
Then we remove the second item:
```
[0, 2]; -> [NgModel(0), NgModel(2)]
```
And finally, if we decide to add an item to the end of the list, we'll already have a control for
index 2, causing the list to look like:
```
[0, 2, 3]; -> [NgModel(0), NgModel(2), NgModel(2)]
```
These changes fix the issue by removing the old control when the `name` of the directive changes.
Fixes#38465.
Fixes#37920.
PR Close#40459
This commit updates the `PatternValidator` class to inherit `AbstractValidatorDirective` to make it conistent with other validators.
Closes angular#42267
PR Close#44887
BREAKING CHANGE: Forms [email] input coercion
Forms [email] input value will be considered as true if it is defined with any value rather
than false and 'false'.
PR Close#42803
Form required validator should not reject objects that contain a length attribute set to zero.
Fixes#30718.
Co-authored-by: Dylan Hunn <dylhunn@gmail.com>
BREAKING CHANGE: objects with a length key set to zero will no longer validate as empty.
This is technically a breaking change, since objects with a key `length` and value `0` will no longer validate as empty. This is a very minor change, and any reliance on this behavior is probably a bug anyway.
PR Close#33729
This implementation change was originally proposed as part of Typed Forms, and will have major consequences for that project as described in the design doc. Submitting it separately will greatly simplify the risk of landing Typed Forms. This change should have no visible impact on normal users of FormControl.
See the Typed Forms design doc here: https://docs.google.com/document/d/1cWuBE-oo5WLtwkLFxbNTiaVQGNk8ipgbekZcKBeyxxo.
PR Close#44316
PR Close#44806
Currently, `ngModel` calls` setValue` after the `resolvedPromise` is resolved.
The promise is resolved _after_ the child template executes. The change detection
is run but `OnPush` views are not updated because they are not marked as dirty.
PR Close#44886
This new feature allows negative indices to wrap around from the back, just like ES2021 `Array.at`. In particular, the following methods accept negative indices, and behave like corresponding Array methods:
* `FormArray.at(index)`: behaves the same as `Array.at(index)`
* `FormArray.insert(index, control)`: behaves the same as `Array.splice(index, 0, control)`
* `FormArray.setControl(index, control)`: behaves the same as `Array.splice(index, 1, control)`
* `FormArray.removeAt(index, control)`: behaves the same as `Array.splice(index, 1)`
Previous work in #44746 and #44631 (by @amitbeck).
Issue #44642.
Co-authored-by: Amit Beckenstein <amitbeck@gmail.com>
PR Close#44848
This functionally dead code was originally introduced via pull request
were added to verify the fix, and the many comments on that issue after
it was closed indicate that it wasn't actually resolved.
In fact, setting `selectedIndex` does absolutely nothing here, since
the selected index is immediately overridden by setting the `value`
property. A working fix (with tests) for the IE/Safari bug is in pull
request #23784. Originally this dead code was removed as part of that PR,
but @AndrewKushnir recommended creating a separate PR for the cleanup.
PR Close#37614
Modified required validator and checkbox validator to inherit abstractValidator.
For every validato type different PR will be raised as discussed in #42378.
Closes#42267
PR Close#44162
This implementation change was originally proposed as part of Typed Forms, and will have major consequences for that project as described in the design doc. Submitting it separately will greatly simplify the risk of landing Typed Forms. This change should have no visible impact on normal users of FormControl.
See the Typed Forms design doc here: https://docs.google.com/document/d/1cWuBE-oo5WLtwkLFxbNTiaVQGNk8ipgbekZcKBeyxxo.
PR Close#44316
Runtime error codes in the Core, Common and Forms packages were not included into the `public-api` group reviews. This commit creates the necessary golden files to keep track of further changes in the runtime codes.
This is a followup from https://github.com/angular/angular/pull/44398#issuecomment-1006910976.
PR Close#44677
Modified email validator to inherit abstractValidator.
For every validato type different PR will be raised as discussed in #42378.
Closes#42267
PR Close#44545
This commit performs some refactoring of the AbstractControl-based classes to employ shared `RuntimeError` class and also updates the code to avoid duplication and improve minification.
PR Close#44398
To make our test output i.e. devmode output more aligned
with what we produce in the NPM packages, or to be more
aligned with what Angular applications will usually consume,
the devmode output is switched from ES5 to ES2015.
Additionally various tsconfigs (outside of Bazel) have been
updated to match with the other parts of the build. The rules
are:
ES2015 for test configurations, ES2020 for actual code that will
end up being shipped (this includes the IDE-only tsconfigs).
PR Close#44505
This commit refactors the code of the base validators class to make it compatible with the property renaming optimization. Currently the code makes an assumption that the field with a specified name (defined as a string) can be found on an object, but with property renaming optimization this is not correct.
PR Close#44500
Make the following fixes:
* When submitting the entire migration in a disabled state, I commented out more code than strictly required
* Responding to some final review comments caused two conditions to become flipped
* Always use explicit checks instead of boolean corecion
* Fix one missed any cast in a test case
PR Close#44540
I previously strengthened some weak types in #44370. One of these fixes exposed an incorrect call into `_reduceChildren` from `_reduceValue`. This was caught in google3 by a caller who was extending `FormGroup` and overriding these methods.
Special thanks to Bart G for catching this issue and suggesting a fix.
PR Close#44483
Allow a FormControl to be reset to its initial value. Provide this feature via a new option in a FormControlOptions interface, based on AbstractControlOptions.
Also, expose the default value as part of the public API. This is part of a feature that has been requested elsewhere (e.g. in #19747).
This was originally proposed as part of typed forms. As discussed in the GDE session (and after with akushnir/alxhub), it is likely better to just reuse the initial value rather than accepting an additional default.
It is desirable to land this separately in order to reduce the scope of the typed forms PR, and make it a types-only change.
Pertains to issue #13721.
PR Close#44434
It is possible to pass arguments to `FormBuilder` using four different formats: value-only, boxed value, control config, and value-array. Currently, these different methods are not well-tested, especially as they interact. This PR will add tests for the variety of different argument shapes.
This was originally inspired by typed forms: when `FormBuilder` becomes typed, all these argument shapes should just work, with correct inferred types.
PR Close#44452
Currently, many of our unit tests are written to use heterogenous groups and arrays, and controls that accept heterogenous values. This PR will make the minimum possible alterations to prepare those usages, mainly by annotating them as untyped controls, etc.
This PR is *not* intended to test typed forms, merely to minimize the size of the upcoming PR. This will allow that PR to be focused on the actual features and tests, rather than boilerplate fixes.
PR Close#44451
It is desirable to land this separately to reduce the scope of the Typed Forms PR, by focusing it only on the new type parameters (rather than incidental strictness fixes).
PR Close#44370
As mentioned in the previous commit, integration tests will be declared
in subpackages of `//integration`. For these tests to still rely on the
NPM packages from `HEAD`, we need to update the visibility.
PR Close#44238
This reverts commit cdf50ff931.
Reverting as this needs a little more work on the documentation side, plus
the `export declare interface` syntax in `model.ts` might have unintended
side effects in g3.
This implementation change was originally proposed as part of Typed Forms, and will have major consequences for that project as described in the design doc. Submitting it separately will greatly simplify the risk of landing Typed Forms. This change should have no visible impact on normal users of FormControl.
See the Typed Forms design doc here: https://docs.google.com/document/d/1cWuBE-oo5WLtwkLFxbNTiaVQGNk8ipgbekZcKBeyxxo.
PR Close#44316
This commit updates the code of the `SelectMultipleControlValueAccessor` to:
- improve typings to make them more precise
- updates the note that refers to IE, but we still can not remove the branch since it's needed for Universal (that uses Domino)
PR Close#44261
Data members in AbstractControl should be eagerly
initialized to address issue/24571. This eliminates the need to
constantly check for truthiness and makes code much more readable.
More PRs to follow to address issue/24571.
PR Close#44292
This commit makes the `FormControlStatus` symbol available as a public API. The symbol itself
was intended to become a part of the public API, but due to the missing re-export, the symbol
remains private.
Fixes#44176.
PR Close#44183
This commit updates the code of the min/max and minlength/maxlength validator directives to inherit `ngOnChanges` hooks from the base class (the `AbstractValidatorDirective` one), rather than implementing the hooks on the child classes. This was needed to avoid issues with hooks inheritance in ViewEngine, but since it's deprecated, the code can be cleaned up.
PR Close#43945
Modified minlength and maxlength validator to inherit abstractValidator
For every validator type different PR will be raised as discussed in #42378.
Closes#42267
PR Close#43998
Modified minlength and maxlength validator to inherit abstractValidator
For every validator type different PR will be raised as discussed in #42378.
Closes#42267
PR Close#43835
RxJS 7 versions prior to 7.4.0 export ES5 code, whereas Angular
applications using RxJS 6 today use ES2015. This was fixed in RxJS 7.4.0
which exposes ES2015 entrypoints as well. This commit updates Angular's
peer dependencies to require the newer RxJS.
PR Close#43748
This commit updates the `node` engines range for all Angular
framework packages to:
* No longer support NodeJS v12 `< 12.20`. This is done because APF v13
uses package export patterns which are only supported as of v12.20.
https://nodejs.org/api/packages.html#packages_subpath_patterns.
* Allows for the latest v16 NodeJS versions. This matches with the CLI
which added NodeJS v16 support with https://github.com/angular/angular-cli/pull/21854.
We already limit this to `>= v16.10.0` in preparation to only
supporting the LTS minors of Node v16.
BREAKING CHANGE: NodeJS versions older than `v12.20.0` are no longer
supported due to the Angular packages using the NodeJS package exports
feature with subpath patterns.
PR Close#43740
With the changes to support APF v13 in the `ng_package` rule, we have
removed the ambiguous `entry_point` attribute. The attribute suggested
that it would be used for determining the primary entry-point input
file. This was not the case as the flat module output file is consulted
for bundling et at. The attribute has been renamed to match its
purposed (renamed to `primary_bundle_name`).
We no longer need to set that attribute because the primary bundle
name is (1) not of relevance for consumers and (2) the rule already
infers the bundle name properly from the Bazel package.
PR Close#43431
This commit updates the logic of the `min` and `max` validators to allow
disabling them dynamically in case `null` is provided as a value. For example: `<input
type="number" [min]="minValue">`, when `minValue` might be set to `null` in a
component class. This should allow `min` and `max` validators to be used for dynamic forms.
Note: similar support was added to the `minLength` and `maxLength`
validators earlier (see #42565).
PR Close#42978
Adds support for TypeScript 4.4. High-level overview of the changes made in this PR:
* Bumps the various packages to `typescript@4.4.2` and `tslib@2.3.0`.
* The `useUnknownInCatchVariables` compiler option has been disabled so that we don't have to cast error objects explicitly everywhere.
* TS now passes in a third argument to the `__spreadArray` call inside child class constructors. I had to update a couple of places in the runtime and ngcc to be able to pick up the calls correctly.
* TS now generates code like `(0, foo)(arg1, arg2)` for imported function calls. I had to update a few of our tests to account for it. See https://github.com/microsoft/TypeScript/pull/44624.
* Our `ngtsc` test setup calls the private `matchFiles` function from TS. I had to update our usage, because a new parameter was added.
* There was one place where we were setting the readonly `hasTrailingComma` property. I updated the usage to pass in the value when constructing the object instead.
* Some browser types were updated which meant that I had to resolve some trivial type errors.
* The downlevel decorators tranform was running into an issue where the Closure synthetic comments were being emitted twice. I've worked around it by recreating the class declaration node instead of cloning it.
PR Close#43281
Currently the error message functions are defined as static methods on a class which means that as soon as one of them is used somewhere, all of them have to be retained. This isn't a problem at the moment, because all of them are behind `ngDevMode` checks, but it's error prone and it's easy to fix.
These changes move them out into functions so that they can be imported individually. It also has the advantage of allowing Webpack to minify the function names.
PR Close#43223
Specifically: narrow the type used for form statuses from string to a union of possible statuses. Change the API methods from any to use the new type.
This is a breaking change. However, as discussed in the PR, breakage seems minimal, and google3 has been prepped to land this.
Background: we uncovered these any typings in the course of design work for typed forms. They could be fixed in a non-breaking manner by piggybacking them on top of the new typed forms generics, but it would be much cleaner to fix them separately if possible.
BREAKING CHANGE:
A new type called `FormControlStatus` has been introduced, which is a union of all possible status strings for form controls. `AbstractControl.status` has been narrowed from `string` to `FormControlStatus`, and `statusChanges` has been narrowed from `Observable<any>` to `Observable<FormControlStatus>`. Most applications should consume the new types seamlessly. Any breakage caused by this change is likely due to one of the following two problems: (1) the app is comparing `AbstractControl.status` against a string which is not a valid status; or, (2) the app is using `statusChanges` events as if they were something other than strings.
PR Close#42952
We can't update the framework to rxjs7 until version 13, because it contains breaking changes, but we can allow users to opt into it since all of our code should be compatible.
These changes expand the allowed version range of rxjs and add an integration test to verify that we don't get compilation errors. Note that we also have a test that runs the AIO examples against rxjs 7 already (#42660).
Fixes#41897.
PR Close#42991
Several new functionalities are possible with this change: the most requested is that callers can now check whether a control has a required validator. Other uses include incrementally changing the validators set without doing an expensive operation to reset all validators.
Closes#13461.
PR Close#42838
If the validator is bound to be `null` then no validation occurs and
attribute is not added to DOM.
For every validator type different PR will be raised as discussed in
https://github.com/angular/angular/pull/42378.
Closes#42267.
PR Close#42565
In combination with the TS `noImplicitOverride` compatibility changes,
we also want to follow the best-practice of adding `override` to
members which are implemented as part of abstract classes. This
commit fixes all instances which will be flagged as part of the
custom `no-implicit-override-abstract` TSLint rule.
PR Close#42512
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
It's perfectly valid for an abstract control not to have a defined parent; yet previously the
types were asserting that AbstractControl#parent is not a null value. This changes correctly
reflects the run-time behavior through the types.
BREAKING CHANGE: Type of AbstractFormControl.parent now includes null
`null` is now included in the types of .parent. If you don't already have a check for this case,
the TypeScript compiler might compain. A v11 migration exists which adds the not-null assertion
operator where necessary.
In an unlikely case your code was testing the parnet against undefined with sitrct equality,
you'll need to change this to `=== null` instead, since the parent is not explicily initialized
with `null` instead of being left `undefined`.
Fixes#16999
PR Close#32671
NG_VALUE_ACCESSOR is a multi injection token, users can and
should expect more than one ControlValueAccessor to be
available (and this is how it is used in @angular/forms).
This is now reflected in the definition of the injection token
by typing it as an array of ControlValueAccessor. The motivating
reason is that using the programmatic Injector api will now
type Injector#get correspondingly.
fixes#29351
BREAKING CHANGES
NG_VALUE_ACCESSOR is now typed as a readonly array rather than
a mutable scalar. It is used as a multi injection token and as
such it should always be expected that more than one accessor
may be returned.
PR Close#29723
This commit ensures that the `updateValueAndValidity` method takes the
`asyncValidator` into consideration to emit on the `statusChanges` observables.
This is necessary so that any subsequent changes are emitted properly to any
subscribers.
Closes#20424Closes#14542
BREAKING CHANGE:
Previously if FormControl, FormGroup and FormArray class instances had async validators
defined at initialization time, the status change event was not emitted once async validator
completed. After this change the status event is emitted into the `statusChanges` observable.
If your code relies on the old behavior, you can filter/ignore this additional status change
event.
PR Close#38354
Prior to this commit, a lot of internal-only class properties and methods (such as `ngOnChanges`)
of the Forms package directives were exposed on angular.io website. These fields are not expected
to be called externally (they are used/invoked by framework only), since they are part of internal
implementations of the following interfaces:
* Angular lifecycle hook interfaces
* ControlValueAccessor interface
* Validator interface
Having these internal-only fields in docs creates unnecessary noise on directive detail pages.
This commit adds the `@nodoc` annotation to these properties and methods to keep fields in the
golden files, but hide them in docs.
PR Close#38583
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
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
A util file is added to forms test package:
- it exposes simpleAsyncValidator, asyncValidator and asyncValidatorReturningObservable validators
- it refactors simpleAsyncValidator and asyncValidator to use common promise creation code
- it exposes currentStateOf allowing to get the validation state of a list of AbstractControl
Closes#37831
PR Close#38020
This commit refactors the way we store validators in AbstractControl-based classes:
in addition to the combined validators function that we have, we also store the original list of validators.
This is needed to have an ability to clean them up later at destroy time (currently it's problematic since
they are combined in a single function).
The change preserves backwards compatibility by making sure public APIs stay the same.
The only public API update is the change to the `AbstractControl` class constructor to extend the set
of possible types that it can accept and process (which should not be breaking).
PR Close#37881
Previously, `registerOnChange` used `hasOwnProperty` to identify if the
property is supported. However, this does not work as the `selectedOptions`
property is an inherited property. This commit fixes this by verifying
the property on the prototype instead.
Closes#37433
PR Close#37620
introduce a boolean to track form groups/arrays own pending async validation to distinguish between pending state due to children and pending state due to own validation
Fixes#10064
PR Close#22575
Error message mention that ngModel and ngModelChange will be removed in Angular v7 but right not now sure when it will be removed so changed it to a future version
PR Close#37643
The method was previously looping through all controls, even after finding at least one that
satisfies the provided condition. This can be a bottleneck with large forms. The new version
of the method returns as soon as a single control which conforms to the condition is found.
PR Close#32534
Use an explicit type guard when checking if a given object is of type AbstractControlOptions,
instead of a simple function returning a boolean value. This allows us to remove manual type
casting when using this function, relying instead on TypeScript to infer correct types.
PR Close#32541
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
Due to an outage with the proxy we rely on for publishing, we need
to temporarily directly publish to NPM using our own angular
credentials again.
PR Close#37378
Tslib version is bound to the TypeScript version used to compile the library. Thus, we shouldn't list `tslib` as a `peerDependencies`. This is because, a user can install libraries which have been compiled with older versions of TypeScript and thus require multiple `tslib` versions to be installed.
Reference: TOOL-1374 and TOOL-1375
Closes: #37188
PR Close#37198
In the code example of the AsyncValidator example there was an aliased
import for the rxjs operator `of`. To align with the RxJS docs it should
just use a plain import of `of`
PR Close#36856
Prior to this commit, number input fields would to fire valueChanges twice: once for `input` events when typing and second for the `change` event when the field lost focus (both events happen at once when using the increment and decrement buttons on the number field).
Fixes#12540
BREAKING CHANGE: Number inputs no longer listen to the `change` event.
* Tests which trigger `change` events need to be updated to trigger `input` events instead.
* The `change` event was in place to support IE9, as we found that `input` events were not fired with backspace or cut actions. If you need to maintain IE9 support, you will need to add a change event listener to number inputs and call the `onChange` method of `NumberValueAccessor` manually.
* Lastly, old versions of WebDriver would synthetically trigger the `change` event on `WebElement.clear` and `WebElement.sendKeys`. If you are using an old version of WebDriver, you may need to update tests to ensure `input` events are triggered. For example, you could use `element.sendKeys(Keys.chord(Keys.CONTROL, "a"), Keys.BACK_SPACE);` in place of `element.clear()`.
PR Close#12540
PR Close#36087
We can remove all of the entry point resolution configuration from the package.json
in our source code as ng_package rule adds the properties automatically and correctly
configures them.
This change simplifies our code base but doesn't have any impact on the package.json
in the distributed npm_packages.
PR Close#36944
Previously, the behavior of the `minLength` and `maxLength` validators
caused confusion, as they appeared to work with numeric values but
did not in fact produce consistent results. This commit fixes the issue
by skipping validation altogether when a numeric value is used.
BREAKING CHANGES:
* The `minLength` and `maxLength` validators now verify that a value has
numeric `length` property and invoke validation only if that's the case.
Previously, falsey values without the length property (such as `0` or
`false` values) were triggering validation errors. If your code relies on
the old behavior, you can include other validators such as [min][1] or
[requiredTrue][2] to the list of validators for a particular field.
[1]: https://angular.io/api/forms/Validators#min
[2]: https://angular.io/api/forms/Validators#requiredTrueCloses#35591
PR Close#36157
Previously, it was not clear that the `minLength` and `maxLength` validators
can only be used with objects that contain a `length` property. This commit
clarifies this.
PR Close#36297
ts-api-guardian uses `require.resolve` to resolve the actual and golden files under bazel. In Windows for these files to be resolved correct the full path including the workspace name as per the MANIFEST entries is required.
This used to be the case until the recent changes done to use npm_integration tests
83c74ceacf/tools/public_api_guard/public_api_guard.bzl (L19)83c74ceacf/tools/public_api_guard/public_api_guard.bzl (L28)
```
bazel test //packages/... --test_tag_filters=api_guard
//packages/animations:animations_api (cached) PASSED in 18.4s
//packages/common:common_api (cached) PASSED in 25.5s
//packages/compiler-cli:compiler_options_api (cached) PASSED in 12.4s
//packages/compiler-cli:error_code_api (cached) PASSED in 11.6s
//packages/core:core_api (cached) PASSED in 20.6s
//packages/core:ng_global_utils_api (cached) PASSED in 13.5s
//packages/elements:elements_api (cached) PASSED in 11.9s
//packages/forms:forms_api (cached) PASSED in 13.9s
//packages/http:http_api (cached) PASSED in 14.8s
//packages/localize:localize_api (cached) PASSED in 6.3s
//packages/platform-browser:platform-browser_api (cached) PASSED in 18.1s
//packages/platform-browser-dynamic:platform-browser-dynamic_api (cached) PASSED in 14.0s
//packages/platform-server:platform-server_api (cached) PASSED in 13.9s
//packages/platform-webworker:platform-webworker_api (cached) PASSED in 13.7s
//packages/platform-webworker-dynamic:platform-webworker-dynamic_api (cached) PASSED in 11.7s
//packages/router:router_api (cached) PASSED in 19.9s
//packages/service-worker:service-worker_api (cached) PASSED in 18.1s
//packages/upgrade:upgrade_api (cached) PASSED in 13.5s
```
Reference: DEV-71
PR Close#36034
Moves the public api .d.ts files from tools/public_api_guard to
goldens/public-api.
Additionally, provides a README in the goldens directory and a script
assist in testing the current state of the repo against the goldens as
well as a command for accepting all changes to the goldens in a single
command.
PR Close#35768
* it's tricky to get out of the runfiles tree with `bazel test` as `BUILD_WORKSPACE_DIRECTORY` is not set but I employed a trick to read the `DO_NOT_BUILD_HERE` file that is one level up from `execroot` and that contains the workspace directory. This is experimental and if `bazel test //:test.debug` fails than `bazel run` is still guaranteed to work as `BUILD_WORKSPACE_DIRECTORY` will be set in that context
* test //integration:bazel_test and //integration:bazel-schematics_test exclusively
* run "exclusive" and "manual" bazel-in-bazel integration tests in their own CI job as they take 8m+ to execute
```
//integration:bazel-schematics_test PASSED in 317.2s
//integration:bazel_test PASSED in 167.8s
```
* Skip all integration tests that are now handled by angular_integration_test except the tests that are tracked for payload size; these are:
- cli-hello-world*
- hello_world__closure
* add & pin @babel deps as newer versions of babel break //packages/localize/src/tools/test:test
@babel/core dep had to be pinned to 7.6.4 or else //packages/localize/src/tools/test:test failed. Also //packages/localize uses @babel/generator, @babel/template, @babel/traverse & @babel/types so these deps were added to package.json as they were not being hoisted anymore from @babel/core transitive.
NB: integration/hello_world__systemjs_umd test must run with systemjs 0.20.0
NB: systemjs must be at 0.18.10 for legacy saucelabs job to pass
NB: With Bazel 2.0, the glob for the files to test `"integration/bazel/**"` is empty if integation/bazel is in .bazelignore. This glob worked under these conditions with 1.1.0. I did not bother testing with 1.2.x as not having integration/bazel in .bazelignore is correct.
PR Close#33927
In https://github.com/angular/angular/pull/33058, we removed support
for the `ngForm` selector in the NgForm directive. We deleted most
of the deprecation notices in that PR, but we missed a paragraph
of documentation in the API docs for NgForm.
This commit removes the outdated paragraph that makes it seem like
the selector is still around and deprecated (as opposed to removed),
as it might confuse users.
PR Close#35435
There is currently a bug in Chrome 80 that makes Array.reduce
not work according to spec. The functionality in forms that
retrieves controls from FormGroups and FormArrays (`form.get`)
relied on Array.reduce, so the Chrome bug broke forms for
many users.
This commit refactors our forms code to rely on Array.forEach
instead of Array.reduce to fix forms while we are waiting
for the Chrome fix to go live.
See https://bugs.chromium.org/p/chromium/issues/detail?id=1049982.
PR Close#35349
we should be documenting when an API is eligible for removal and not when it will be removed.
The actual removal depends on many factors, e.g. if we were able to automate the refactoring to
the recommended API in time or not.
PR Close#35263
The value changes emitted additionally when enable disable were called
documented the above behaviour in AbstractControl class documentaion
Fixes#34407
PR Close#34497
The major one that affects the angular repo is the removal of the bootstrap attribute in nodejs_binary, nodejs_test and jasmine_node_test in favor of using templated_args --node_options=--require=/path/to/script. The side-effect of this is that the bootstrap script does not get the require.resolve patches with explicitly loading the targets _loader.js file.
PR Close#34736
Both `MinLengthValidator` and `MaxLengthValidator` accepted only string inputs for the length required, which throws with Ivy and `fullTemplateTypeCheck` enabled:
<!-- min = 2 in the component -->
<input [minlength]="min">
with:
Type 'number' is not assignable to type 'string | undefined'
This relaxes the accepted type to `string | number` to avoid breakage when developers switch to Ivy and fTTC.
PR Close#32057
The major one that affects the angular repo is the removal of the bootstrap attribute in nodejs_binary, nodejs_test and jasmine_node_test in favor of using templated_args --node_options=--require=/path/to/script. The side-effect of this is that the bootstrap script does not get the require.resolve patches with explicitly loading the targets _loader.js file.
PR Close#34589
With 5cecd97493 we intended to expand
the input type of the `disabled` input of the `NgModel` directive.
Read more about the reason for this in the actual commit message.
Currently though, the acceptance coercion member does not have any
effect. This is because the acceptance member needs to refer to the
actual input property name, and not to the public input name.
`disabled` corresponds to the `isDisabled` property.
PR Close#34502
NgModel internally coerces any arbitrary value that will assigned
to the `disabled` `@Input` to a boolean. This has been done to
support the common case where developers set the disabled attribute
without a value. For example:
```html
<input type="checkbox" [(ngModel)]="value" disabled>
```
This worked in View Engine without any errors because inputs were
not strictly checked. In Ivy though, developers can opt-in into
strict template type checking where the attribute would be flagged.
This is because the `NgModel#isDisabled` property type-wise only
accepts a `boolean`. To ensure that the common pattern described
above can still be used, and to reflect the actual runtime behavior,
we should add an acceptance member that makes it work without type
checking errors.
Using a coercion member means that this is not a breaking change.
PR Close#34438
Currently we only run Saucelabs on PRs using the legacy View Engine
build. Switching that build to Ivy is not trivial and there are various
options:
1. Updating the R3 switches to use POST_R3 by default. At first glance,
this doesn't look easy because the current ngtsc switch logic seems to
be unidirectional (only PRE_R3 to POST_R3).
2. Updating the legacy setup to run with Ivy. This sounds like the easiest
solution at first.. but it turns out to be way more complicated. Packages
would need to be built with ngtsc using legacy tools (i.e. first building
the compiler-cli; and then building packages) and View Engine only tests
would need to be determined and filtered out. Basically it will result in
re-auditing all test targets. This is contradictory to the fact that we have
this information in Bazel already.
3. Creating a new job that runs tests on Saucelabs with Bazel. We specify
fine-grained test targets that should run. This would be a good start
(e.g. acceptance tests) and also would mean that we do not continue maintaining
the legacy setup..
This commit implements the third option as it allows us to move forward
with the general Bazel migration. We don't want to spend too much time
on our legacy setup since it will be removed anyway in the future.
PR Close#34277
This commit fixes a compatibility bug where pre-order lifecycle
hooks (onInit, doCheck, OnChanges) for directives on the same
host node were executed based on the order the directives were
matched, rather than the order the directives were instantiated
(i.e. injection order).
This discrepancy can cause issues with forms, where it is common
to inject NgControl and try to extract its control property in
ngOnInit. As the NgControl directive is injected, it should be
instantiated before the control value accessor directive (and
thus its hooks should run first). This ensures that the NgControl
ngOnInit can set up the form control before the ngOnInit
for the control value accessor tries to access it.
Closes#32522
PR Close#34026
This is a breaking change in nodejs rules 0.40.0 as part of the API review & cleanup for the 1.0 release. Their APIs are identical as ts_web_test was just karma_web_test without the config_file attribute.
PR Close#33802
Changed `setValue` documentation for throwing an error as it contained a grammar
mistake and also may have caused ambiguity around when exactly the
method would throw.
PR Close#33126
BREAKING CHANGE:
We no longer directly have a direct depedency on `tslib`. Instead it is now listed a `peerDependency`.
Users not using the CLI will need to manually install `tslib` via;
```
yarn add tslib
```
or
```
npm install tslib --save
```
PR Close#32167
Removes the deprecated `ngForm` element selector and all of the code related to it.
BREAKING CHANGES:
* `<ngForm></ngForm>` can no longer be used as a selector. Use `<ng-form></ng-form>` instead.
* The `NgFromSelectorWarning` directive has been removed.
* `FormsModule.withConfig` has been removed. Use the `FormsModule` directly.
PR Close#33058
As mentioned in the previous commit, the regexp used by
`Validators.email()` is a slightly enhanced version of the
[WHATWG one](https://html.spec.whatwg.org/multipage/input.html#valid-e-mail-address).
This commit refactors the regexp (without changing its behavior) to make
it more closely match the format of WHATWG version, so that it is easier
for people to compare it against the WHATWG one and understand the
differences.
The main changes were:
- Changing the order of characters/character classes inside `[...]`;
e.g. `[A-Za-z]` --> `[a-zA-Z]`
- Mark all groups as non-capturing (since we do not use the captured
values); e.g. `(foo)` --> `(?:foo)`
(This could theoretically also have a positive performance impact, but
I suspect JavaScript engines are already optimizing away capturing
groups when they are not used.)
PR Close#32961
Previously, there was no documentation of what `Validators.email()`
expects as a valid e-mail address, making it difficult for people to
determine whether it covers their requirements or not. Even more so that
the used pattern slightly deviates from the
[WHATWG version](https://html.spec.whatwg.org/multipage/input.html#valid-e-mail-address).
One's only option was to look at the source code and try to decipher the
regexp pattern.
This commit adds a high-level description of the validator and mentions
its similarity to and differences from the WHATWG version. It also adds
a brief explanation of the regexp's behavior and references for more
information in the source code to provide more context to
maintainers/users trying to understand the implementation in the future.
Fixes#18985Fixes#25186Closes#32747
PR Close#32961
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
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
Fixes all TypeScript failures caused by enabling the `--strict`
flag for test source files. We also want to enable the strict
options for tests as the strictness enforcement improves the
overall codehealth, unveiled common issues and additionally it
allows us to enable `strict` in the `tsconfig.json` that is picked
up by IDE's.
PR Close#30993
This method is a more convenient and efficient way of removing all
components from a FormArray. Before it, we needed to loop the FormArray
removing each component until empty.
Resolves#18531
PR Close#28918
This PR also changes the name of NgNoValidate` to `ɵNgNoValidate`. This is because `ngcc` requires the node to retain the original name while dts bundler will rename the node is it's only exported using the aliases.
Example typings files:
```ts
declare class NgNoValidate{
}
export {NgNoValidateas ɵNgNoValidate}
```
will be emitted as
```ts
export declare class ɵNgNoValidate {
}
```
PR Close#28854
This change helps highlight certain misoptimizations with Closure
compiler. It is also stylistically preferable to consistently use index
access on index sig types.
Roughly, when one sees '.foo' they know it is always checked for typos
in the prop name by the type system (unless 'any'), while "['foo']" is
always not.
Once all angular repos are conforming this will become a tsetse.info
check, enforced by bazel.
PR Close#28937
Since we build and publish the individual packages
using Bazel and `build.sh` has been removed, we can
safely remove the `rollup.config.js` files which are no
longer needed because the `ng_package` bazel rule
automatically handles the rollup settings and globals.
PR Close#28646
BREAKING CHANGE
Previous to this change, when a control was reset, value and status change
events would be emitted before the control was reset to pristine. As a
result, if one were to check a control's pristine state in a valueChange
listener, it would appear that the control was still dirty after reset.
This change delays emission of value and status change events until after
controls have been marked pristine. This means the pristine state will be
reset as expected if one checks in a listener.
Theoretically, there could be applications depending on checking whether a
control *used to be dirty*, so this is marked as breaking. In these cases,
apps should cache the state on the app side before calling reset.
Fixes#28130
PR Close#28395
@angular/forms declares several directives and a module which are not
exported from the package via the entrypoint, either intentionally or as a
historical accident.
Ivy's locality principle necessitates that directives used in user code be
importable from the package which defines them. This requires these forms
directives to be exported.
Several directives which define ControlValueAccessors are exported:
* NumberValueAccessor
* RangeValueAccessor
A few more directives and a module are exported privately (with a ɵ prefix):
* NgNoValidate
* NgSelectMultipleOption
* InternalFormsSharedModule
PR Close#27743
Internally getError and hasError call the AbstractControl#get method which takes `path: Array<string | number> | string` as input, since there are different ways to traverse the AbstractControl tree.
This change matches the method signitures of all methods that use this.
PR Close#20211