Commit graph

448 commits

Author SHA1 Message Date
Paul Gschwendtner
c9415e4d75 build: ensure bootstrap transitive runfiles are made available (#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
2022-12-19 19:50:41 +00:00
Paul Gschwendtner
20551503fa build: replace _es2015 shorthand with more flexible _files suffix (#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
2022-12-19 19:50:41 +00:00
sr5434
02691a74bb refactor(forms): make FormBuilder classes provided in root (#48245)
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
2022-12-06 13:29:41 -08:00
Derek Cormier
f37dd0fc96 build(bazel): create AIO example playgrounds for manual testing
After the bazel migration, AIO examples are no longer fully formed in
the source tree.
2022-11-22 13:51:16 -07:00
Derek Cormier
bc1e93d639 build(bazel): refactor aio example e2es to fix windows performance
Use the same config flag to enable local vs npm deps as aio.
2022-11-22 13:51:16 -07:00
Derek Cormier
22a317de3d build(bazel): stamp targets to build, test, and serve aio against
first party deps

Architect is not compatible with disabling the rules_nodejs linker so
these targets must use npm_link to link first party deps
2022-11-22 13:51:16 -07:00
Derek Cormier
7a134cf41a build(bazel): incrementally run aio example e2e tests
Replaces the workflow where all example e2es are run at once
2022-11-22 13:51:16 -07:00
Derek Cormier
431c562815 build(bazel): add bazel targets for aio doc generation
This is an incremental step to produce dgeni output with bazel. The
generated outputs are not yet used by other targets.
2022-11-22 13:51:16 -07:00
Wooshaah
7fbb53f52d docs(forms): fix typos in removeValidators and hasValidator usage notes (#48144)
PR Close #48144
2022-11-22 11:39:02 -08:00
Matthieu Riegler
d321880440 fix(forms): FormBuilder.group return right type with shorthand parameters. (#48084)
Extract AbstractControlOptions from type when used in shorthand parameters on FormBuilder.group

Fixes 48073

PR Close #48084
2022-11-17 11:04:54 -08:00
Kristiyan Kostadinov
779a76fa5a fix(forms): don't mutate validators array (#47830)
Fixes that the `AbstractControl` was mutating the validators arrays being passed into the constructor an helper methods like `setValidators`.

Fixes #47827.

PR Close #47830
2022-11-17 09:36:14 -08:00
Dylan Hunn
604cdb7307 fix(forms): Improve a very commonly viewed error message by adding a guide. (#47969)
[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
2022-11-07 16:00:06 -08:00
Pawel Kozlowski
9bfedb1306 Revert "fix(forms): don't mutate validators array (#47830)" (#47845)
This reverts commit 0329c13e95.

PR Close #47845
2022-10-25 10:05:17 +02:00
Kristiyan Kostadinov
0329c13e95 fix(forms): don't mutate validators array (#47830)
Fixes that the `AbstractControl` was mutating the validators arrays being passed into the constructor an helper methods like `setValidators`.

Fixes #47827.

PR Close #47830
2022-10-24 14:12:56 +02:00
Alan Agius
1b9fd46d14 feat(core): add support for Node.js version 18 (#47730)
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
2022-10-11 17:21:19 +00:00
Dylan Hunn
96b7fe93af fix(forms): call setDisabledState on ControlValueAcessor when control is enabled (#47576)
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
2022-10-11 16:03:01 +00:00
Ferdinand Malcher
a8569e3802 feat(forms): export forms utility functions: isFormArray, isFormGroup… (#47718)
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
2022-10-10 19:43:26 +00:00
Álvaro Martínez
bf6679a579 docs(forms): setErrors emitEvent default value (#47546)
PR Close #47546
2022-10-06 20:24:52 +00:00
onrails
ec9ee8e2bb docs(forms): correcting description verbs of formGroup methods (#47399)
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
2022-09-12 19:05:22 -07:00
Kristiyan Kostadinov
4a13210ecd fix(forms): don't prevent default behavior for forms with method="dialog" (#47308)
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
2022-09-09 14:26:48 -07:00
Jeremy Elbourn
aa14662562 refactor(forms): remove unnecesary null (#47238)
These null values are unused and unecessary. I suspect it's a remnant from when the codebase was transpiled to Dart.

PR Close #47238
2022-09-06 09:57:37 -07:00
Dylan Hunn
b302797de4 fix(forms): Correctly infer FormBuilder types involving [value, validators] shorthand in more cases. (#47034)
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
2022-08-17 11:32:15 +00:00
Mladen Jakovljević
621c38813f refactor: improve disabled attribute warning (#47041)
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
2022-08-08 11:33:52 -07:00
Cédric Exbrayat
426af91a42 feat(forms): add FormBuilder.record() method (#46485)
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
2022-07-15 22:02:44 +00:00
Cédric Exbrayat
089efa1ac9 refactor(forms): simplify group builder function (#46844)
Applies the same logic that we have in the `control` function.

PR Close #46844
2022-07-15 22:02:20 +00:00
Uday Sony
c0ca3fc71a fix(forms): expose ControlConfig in public API (#46594)
This commit exposes the ControlConfig as a public API, so that the symbol can be used in applications.

PR Close #46594
2022-07-12 17:45:37 +00:00
John Vandenberg
c14c701775 docs: fix spelling (#46713)
PR Close #46713
2022-07-08 20:54:52 +00:00
Dylan Hunn
e9b5dac9ec fix(forms): Move all remaining errors in Forms to use RuntimeErrorCode. (#46654)
RuntimeErrorCode allows for better tree-shaking, and unique codes for each error.

PR Close #46654
2022-07-06 09:49:39 -07:00
Dylan Hunn
0a5c8c0bc4 fix(forms): Convert existing reactive errors to use RuntimeErrorCode. (#46560)
This allows for better tree-shakability, as well as the addition of guides in the future as needed.

PR Close #46560
2022-06-29 10:15:42 -07:00
Dylan Hunn
f6a096e3d4 fix(forms): Update a Forms validator error to use RuntimeError (#46537)
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
2022-06-28 11:32:54 -07:00
KMathy
7316fa71c4 docs(forms): add usage notes (#46472)
Add usage notes for removeValidators and hasValidators to better understand how to use these functions

PR Close #46472
2022-06-24 13:28:50 -07:00
Cédric Exbrayat
dedbc2c5d5 refactor(forms): remove unused internal function (#46479)
The `isFormControlOptions` function is never used, and can be safely removed as it is not a public API.

PR Close #46479
2022-06-24 13:10:37 -07:00
Totati
81150313f6 docs(forms): fix FormRecord usage notes (#46299)
FormRecod usegaesNotes were like it accetps simple object like a FormBuilder.
PR Close #46299
2022-06-08 20:52:22 +00:00
Dylan Hunn
f18e1739b8 fix(forms): allow FormBuilder.group(...) to accept optional fields. (#46253)
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
2022-06-06 10:14:19 -07:00
Dylan Hunn
f12cf2b89b docs(forms): Amend the FormGroupDirective docs to indicate it also works with FormRecord. (#46235)
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
2022-06-06 10:11:15 -07:00
Dylan Hunn
0e14df697a fix(forms): Warn on FormControls that are constructed with both options and asyncValidators.
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.
2022-05-19 15:49:02 -07:00
Dylan Hunn
37bf6932e9 fix(forms): Add a nonNullable option to FormControl for consistency.
DEPRECATED:

The `initialValueIsDefault` option has been deprecated and replaced with the otherwise-identical `nonNullable` option, for the sake of naming consistency.
2022-05-19 15:49:02 -07:00
George Kalpakas
cd0096df2c docs: fix inline JSDoc tags (@see --> @link) (#46040)
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
2022-05-19 13:32:20 -07:00
Dylan Hunn
038ba8adea revert "fix(forms): Value and RawValue should be part of the public API." (#46023)
As per discussion on #fw-forms, this reverts #45978 (although the more in-depth comments were kept).

PR Close #46023
2022-05-17 22:48:03 +00:00
Dylan Hunn
a4b7a3cf4a docs(forms): Make some fixes to typed forms docs: (#46023)
* `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
2022-05-17 22:48:03 +00:00
Dylan Hunn
dba6a60861 fix(forms): Value and RawValue should be part of the public API. (#45978)
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
2022-05-16 18:36:53 +00:00
Dylan Hunn
e441ff44b4 fix(forms): Prevent FormBuilder from distributing unions to control types. (#45942)
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
2022-05-10 12:36:37 -07:00
Dylan Hunn
43ba4ab9da fix(forms): Allow NonNullableFormBuilder to be injected. (#45904)
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
2022-05-09 17:31:48 -07:00
Dylan Hunn
2dbdebc646 feat(forms): Add FormBuilder.nonNullable. (#45852)
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
2022-05-04 12:46:05 -07:00
Dylan Hunn
fce50637c5 docs(forms): Add documentation for typed forms. (#45841)
Update the JSDoc on forms model classes with more specific information about the new types.

PR Close #45841
2022-05-02 15:03:40 -07:00
Paul Gschwendtner
68597bb0ca feat(bazel): speed up dev-turnaround by bundling types only when packaging (#45405)
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
2022-04-21 11:09:39 -07:00
Dylan Hunn
ff3f5a8d12 fix(forms): Fix a typing bug in FormBuilder. (#45684)
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
2022-04-20 09:15:46 -07:00
Dylan Hunn
e0a2248b32 feat(forms): Add a FormRecord type. (#45607)
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
2022-04-14 14:59:10 -07:00
Dylan Hunn
89d299105a feat(forms): Implement strict types for the Angular Forms package. (#43834)
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
2022-04-12 17:37:04 +00:00
Hossein Mousavi
5adfe8ef24 docs(forms): remove the incorrect set value from previous commit (#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
2022-04-07 21:00:25 +00:00