This change also decorelate the `reset` type argument from `TValue` by adding a 3rd generic parameter to `AbstractControl`.
This improves the typings overall.
PR Close#55860
This aligns with how angular/components marks their hidden APIs.
`@nodoc` has been broken since the switch to adev, this change should
properly hide the APIs again.
PR Close#61194
Adds the `markAllAsDirty` method to the `AbstractControl` class. This method will mark the control and all its
descendants as dirty.
I pretty much just duplicated the behaviour and tests of `markAllAsTouched`.
Fixes#55990
PR Close#58663
Instead of relying on Microsoft's API extractor for `d.ts` bundling,
we are switching to Rollup-based `.d.ts` bundling.
This allows us to support code spliting, even for `.d.ts` files,
allowing for relative imports to be used between entry-points, without
ending up duplicating `.d.ts` definitions in two files. This would otherwise cause
problems with assignability of types.
It also nicely integrates into our existing rollup configuration, and
overall simplifies the `ng_package` rule even further!
Notably `tsup` also uses this rollup plugin, and it seems to work well.
Keep in mind that Microsoft's API extractor is pretty hard to integrate,
caused many problems in the past, and isn't capable of code splitting.
This aligns our d.ts bundling with the .mjs bundling (great alignment).
PR Close#60321
This commit makes the host bindings of `NgControlStatus[Group]`
compatible with `OnPush` components. Note that this intentionally _does not_
expose any new APIs in the forms module. The goal is only to remove
unpreventable `ExpressionChangedAfterItHasBeenCheckedError` in the forms
code that developers do not have control over.
PR Close#55720
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
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
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
If a library is compiling with Angular v16.1.0, the library will break
for users that are still on Angular v16.0.x. This happens because the
`DirectiveDeclaration` or `ComponentDeclaration` types are not expecting
an extra field for `signals` metadata. This field was only added to the
generic types in `16.1.0`- so compilations fail with errors like this:
```
Error: node_modules/@angular/material/icon/index.d.ts:204:18 -
error TS2707: Generic type 'ɵɵComponentDeclaration' requires between 7 and 9 type arguments.
```
To fix this, we quickly roll back the code for inserting this metadata
field. That way, libraries remain compatible with all v16.x framework
versions.
We continue to include the `signals` metadata if `signals: true` is set.
This is not public API anyway right now- so cannot happen- but imagine
we expose some signal APIs in e.g. 16.2.x, then we'd need this metadata
and can reasonably expect signal-component library users to use a more
recent framework core version.
PR Close#50714
This commit adds the `signals: boolean` property to the internal
directive/component metadata. This does not add it to the public API
yet, as the feature has no internal support other than compiler
detection.
PR Close#49981
Adds support for marking a directive input as required. During template type checking, the compiler will verify that all required inputs have been specified and will raise a diagnostic if one or more are missing. Some specifics:
* Inputs are marked as required by passing an object literal with a `required: true` property to the `Input` decorator or into the `inputs` array.
* Required inputs imply that the directive can't work without them. This is why there's a new check that enforces that all required inputs of a host directive are exposed on the host.
* Required input diagnostics are reported through the `OutOfBandDiagnosticRecorder`, rather than generating a new structure in the TCB, because it allows us to provide a better error message.
* Currently required inputs are only supported during AOT compilation, because knowing which bindings are present during JIT can be tricky and may lead to increased bundle sizes.
Fixes#37706.
PR Close#49468
This reverts commit 13dd614cd1.
This breaks a g3 Typescript compilation tests where diagnostics are
expected for a missing input in the component.
PR Close#49467
Adds support for marking a directive input as required. During template type checking, the compiler will verify that all required inputs have been specified and will raise a diagnostic if one or more are missing. Some specifics:
* Inputs are marked as required by passing an object literal with a `required: true` property to the `Input` decorator or into the `inputs` array.
* Required inputs imply that the directive can't work without them. This is why there's a new check that enforces that all required inputs of a host directive are exposed on the host.
* Required input diagnostics are reported through the `OutOfBandDiagnosticRecorder`, rather than generating a new structure in the TCB, because it allows us to provide a better error message.
* Currently required inputs are only supported during AOT compilation, because knowing which bindings are present during JIT can be tricky and may lead to increased bundle sizes.
Fixes#37706.
PR Close#49453
This reverts commit 1a6ca68154.
This breaks tests in google3 which might be depending on private APIs. We
need to update these tests before we can land this PR.
PR Close#49449
Adds support for marking a directive input as required. During template type checking, the compiler will verify that all required inputs have been specified and will raise a diagnostic if one or more are missing. Some specifics:
* Inputs are marked as required by passing an object literal with a `required: true` property to the `Input` decorator or into the `inputs` array.
* Required inputs imply that the directive can't work without them. This is why there's a new check that enforces that all required inputs of a host directive are exposed on the host.
* Required input diagnostics are reported through the `OutOfBandDiagnosticRecorder`, rather than generating a new structure in the TCB, because it allows us to provide a better error message.
* Currently required inputs are only supported during AOT compilation, because knowing which bindings are present during JIT can be tricky and may lead to increased bundle sizes.
Fixes#37706.
PR Close#49304
`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
[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
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
This is the compile-time implementation of the `hostDirectives` feature plus a little bit of runtime code to illustrate how the newly-generated code will plug into the runtime. It works by creating a call to the new `ɵɵHostDirectivesFeature` feature whenever a directive has a `hostDirectives` field. Afterwards `ɵɵHostDirectivesFeature` will patch a new function onto the directive definition that will be invoked during directive matching.
For example, if we take the following definition:
```ts
@Directive({
hostDirectives: [HostA, {directive: HostB, inputs: ['input: alias']}]
})
class MyDir {}
```
Will compile to:
```js
MyDir.ɵdir = ɵɵdefineComponent({
features: [ɵɵHostDirectivesFeature([HostA, {
directive: HostB,
inputs: {
input: "alias"
}
}])]
});
```
The template type checking is implemented during directive matching by adding the host directives applied on the host to the array of matched directives whenever the host is matched in a template.
Relates to #8785.
PR Close#46868
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
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.
* `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
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
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
This commit adds a type field to .d.ts metadata for directives, components,
and pipes which carries a boolean literal indicating whether the given type
is standalone or not. For backwards compatibility, this flag defaults to
`false`.
Tests are added to validate that standalone types coming from .d.ts files
can be correctly imported into new standalone components.
PR Close#45672