fix(forms): handle standalone <form> tag correctly in NgControlStatusGroup directive (#40344)
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
This commit is contained in:
committed by
Andrew Scott
parent
7a819caef6
commit
fdbd3cae8a
@@ -6,39 +6,39 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Directive, Self} from '@angular/core';
|
||||
import {Directive, Optional, Self} from '@angular/core';
|
||||
|
||||
import {AbstractControlDirective} from './abstract_control_directive';
|
||||
import {ControlContainer} from './control_container';
|
||||
import {NgControl} from './ng_control';
|
||||
|
||||
export class AbstractControlStatus {
|
||||
private _cd: AbstractControlDirective;
|
||||
private _cd: AbstractControlDirective|null;
|
||||
|
||||
constructor(cd: AbstractControlDirective) {
|
||||
constructor(cd: AbstractControlDirective|null) {
|
||||
this._cd = cd;
|
||||
}
|
||||
|
||||
get ngClassUntouched(): boolean {
|
||||
return this._cd.control ? this._cd.control.untouched : false;
|
||||
return this._cd?.control?.untouched ?? false;
|
||||
}
|
||||
get ngClassTouched(): boolean {
|
||||
return this._cd.control ? this._cd.control.touched : false;
|
||||
return this._cd?.control?.touched ?? false;
|
||||
}
|
||||
get ngClassPristine(): boolean {
|
||||
return this._cd.control ? this._cd.control.pristine : false;
|
||||
return this._cd?.control?.pristine ?? false;
|
||||
}
|
||||
get ngClassDirty(): boolean {
|
||||
return this._cd.control ? this._cd.control.dirty : false;
|
||||
return this._cd?.control?.dirty ?? false;
|
||||
}
|
||||
get ngClassValid(): boolean {
|
||||
return this._cd.control ? this._cd.control.valid : false;
|
||||
return this._cd?.control?.valid ?? false;
|
||||
}
|
||||
get ngClassInvalid(): boolean {
|
||||
return this._cd.control ? this._cd.control.invalid : false;
|
||||
return this._cd?.control?.invalid ?? false;
|
||||
}
|
||||
get ngClassPending(): boolean {
|
||||
return this._cd.control ? this._cd.control.pending : false;
|
||||
return this._cd?.control?.pending ?? false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,7 +99,7 @@ export class NgControlStatus extends AbstractControlStatus {
|
||||
host: ngControlStatusHost
|
||||
})
|
||||
export class NgControlStatusGroup extends AbstractControlStatus {
|
||||
constructor(@Self() cd: ControlContainer) {
|
||||
constructor(@Optional() @Self() cd: ControlContainer) {
|
||||
super(cd);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user