mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
refactor(forms): use optional chaining for safer method calls in form directives
Simplifies null checks by leveraging optional chaining when invoking
optional callbacks
(cherry picked from commit 8b3b069be7)
This commit is contained in:
committed by
Andrew Kushnir
parent
ae3c8fbc38
commit
2c3f3cc336
@@ -264,7 +264,7 @@ export abstract class AbstractControlDirective {
|
||||
* Resets the control with the provided value if the control is present.
|
||||
*/
|
||||
reset(value: any = undefined): void {
|
||||
if (this.control) this.control.reset(value);
|
||||
this.control?.reset(value);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -41,10 +41,8 @@ export class AbstractFormGroupDirective extends ControlContainer implements OnIn
|
||||
|
||||
/** @docs-private */
|
||||
ngOnDestroy(): void {
|
||||
if (this.formDirective) {
|
||||
// Remove the group from its parent group.
|
||||
this.formDirective.removeFormGroup(this);
|
||||
}
|
||||
// Remove the group from its parent group.
|
||||
this.formDirective?.removeFormGroup(this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -256,9 +256,9 @@ export class NgForm extends ControlContainer implements Form, AfterViewInit {
|
||||
removeControl(dir: NgModel): void {
|
||||
resolvedPromise.then(() => {
|
||||
const container = this._findContainer(dir.path);
|
||||
if (container) {
|
||||
container.removeControl(dir.name);
|
||||
}
|
||||
|
||||
container?.removeControl(dir.name);
|
||||
|
||||
this._directives.delete(dir);
|
||||
});
|
||||
}
|
||||
@@ -288,9 +288,7 @@ export class NgForm extends ControlContainer implements Form, AfterViewInit {
|
||||
removeFormGroup(dir: NgModelGroup): void {
|
||||
resolvedPromise.then(() => {
|
||||
const container = this._findContainer(dir.path);
|
||||
if (container) {
|
||||
container.removeControl(dir.name);
|
||||
}
|
||||
container?.removeControl?.(dir.name);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -278,7 +278,7 @@ export class NgModel extends NgControl implements OnChanges, OnDestroy {
|
||||
|
||||
/** @docs-private */
|
||||
ngOnDestroy(): void {
|
||||
this.formDirective && this.formDirective.removeControl(this);
|
||||
this.formDirective?.removeControl(this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -357,24 +357,20 @@ export abstract class AbstractFormDirective
|
||||
}
|
||||
|
||||
private _cleanUpFormContainer(dir: FormArrayName | FormGroupName): void {
|
||||
if (this.form) {
|
||||
const ctrl: any = this.form.get(dir.path);
|
||||
if (ctrl) {
|
||||
const isControlUpdated = cleanUpFormContainer(ctrl, dir);
|
||||
if (isControlUpdated) {
|
||||
// Run validity check only in case a control was updated (i.e. view validators were
|
||||
// removed) as removing view validators might cause validity to change.
|
||||
ctrl.updateValueAndValidity({emitEvent: false});
|
||||
}
|
||||
const ctrl: any = this.form?.get(dir.path);
|
||||
if (ctrl) {
|
||||
const isControlUpdated = cleanUpFormContainer(ctrl, dir);
|
||||
if (isControlUpdated) {
|
||||
// Run validity check only in case a control was updated (i.e. view validators were
|
||||
// removed) as removing view validators might cause validity to change.
|
||||
ctrl.updateValueAndValidity({emitEvent: false});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private _updateRegistrations() {
|
||||
this.form._registerOnCollectionChange(this._onCollectionChange);
|
||||
if (this._oldForm) {
|
||||
this._oldForm._registerOnCollectionChange(() => {});
|
||||
}
|
||||
this._oldForm?._registerOnCollectionChange(() => {});
|
||||
}
|
||||
|
||||
private _updateValidators() {
|
||||
|
||||
@@ -179,9 +179,7 @@ export class FormControlName extends NgControl implements OnChanges, OnDestroy {
|
||||
|
||||
/** @docs-private */
|
||||
ngOnDestroy(): void {
|
||||
if (this.formDirective) {
|
||||
this.formDirective.removeControl(this);
|
||||
}
|
||||
this.formDirective?.removeControl(this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -286,7 +286,7 @@ export class NgSelectOption implements OnDestroy {
|
||||
@Input('value')
|
||||
set value(value: any) {
|
||||
this._setElementValue(value);
|
||||
if (this._select) this._select._writeValueAfterRender();
|
||||
this._select?._writeValueAfterRender();
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
@@ -296,9 +296,7 @@ export class NgSelectOption implements OnDestroy {
|
||||
|
||||
/** @docs-private */
|
||||
ngOnDestroy(): void {
|
||||
if (this._select) {
|
||||
this._select._optionMap.delete(this.id);
|
||||
this._select._writeValueAfterRender();
|
||||
}
|
||||
this._select?._optionMap.delete(this.id);
|
||||
this._select?._writeValueAfterRender();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,10 +120,9 @@ export function cleanUpControl(
|
||||
// case. We still check the presence of `valueAccessor` before invoking its methods to make sure
|
||||
// that cleanup works correctly if app code or tests are setup to ignore the error thrown from
|
||||
// `selectValueAccessor`. See https://github.com/angular/angular/issues/40521.
|
||||
if (dir.valueAccessor) {
|
||||
dir.valueAccessor.registerOnChange(noop);
|
||||
dir.valueAccessor.registerOnTouched(noop);
|
||||
}
|
||||
|
||||
dir?.valueAccessor?.registerOnChange(noop);
|
||||
dir?.valueAccessor?.registerOnTouched(noop);
|
||||
|
||||
cleanUpValidators(control, dir);
|
||||
|
||||
|
||||
@@ -162,9 +162,7 @@ abstract class AbstractValidatorDirective implements Validator, OnChanges {
|
||||
const input = this.normalizeInput(changes[this.inputName].currentValue);
|
||||
this._enabled = this.enabled(input);
|
||||
this._validator = this._enabled ? this.createValidator(input) : nullValidator;
|
||||
if (this._onChange) {
|
||||
this._onChange();
|
||||
}
|
||||
this._onChange?.();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -997,8 +997,8 @@ export abstract class AbstractControl<
|
||||
this.touched = true;
|
||||
|
||||
const sourceControl = opts.sourceControl ?? this;
|
||||
if (this._parent && !opts.onlySelf) {
|
||||
this._parent.markAsTouched({...opts, sourceControl});
|
||||
if (!opts.onlySelf) {
|
||||
this._parent?.markAsTouched({...opts, sourceControl});
|
||||
}
|
||||
|
||||
if (changed && opts.emitEvent !== false) {
|
||||
@@ -1087,8 +1087,8 @@ export abstract class AbstractControl<
|
||||
control.markAsUntouched({onlySelf: true, emitEvent: opts.emitEvent, sourceControl});
|
||||
});
|
||||
|
||||
if (this._parent && !opts.onlySelf) {
|
||||
this._parent._updateTouched(opts, sourceControl);
|
||||
if (!opts.onlySelf) {
|
||||
this._parent?._updateTouched(opts, sourceControl);
|
||||
}
|
||||
|
||||
if (changed && opts.emitEvent !== false) {
|
||||
@@ -1131,8 +1131,8 @@ export abstract class AbstractControl<
|
||||
this.pristine = false;
|
||||
|
||||
const sourceControl = opts.sourceControl ?? this;
|
||||
if (this._parent && !opts.onlySelf) {
|
||||
this._parent.markAsDirty({...opts, sourceControl});
|
||||
if (!opts.onlySelf) {
|
||||
this._parent?.markAsDirty({...opts, sourceControl});
|
||||
}
|
||||
|
||||
if (changed && opts.emitEvent !== false) {
|
||||
@@ -1184,8 +1184,8 @@ export abstract class AbstractControl<
|
||||
control.markAsPristine({onlySelf: true, emitEvent: opts.emitEvent});
|
||||
});
|
||||
|
||||
if (this._parent && !opts.onlySelf) {
|
||||
this._parent._updatePristine(opts, sourceControl);
|
||||
if (!opts.onlySelf) {
|
||||
this._parent?._updatePristine(opts, sourceControl);
|
||||
}
|
||||
|
||||
if (changed && opts.emitEvent !== false) {
|
||||
@@ -1230,8 +1230,8 @@ export abstract class AbstractControl<
|
||||
(this.statusChanges as EventEmitter<FormControlStatus>).emit(this.status);
|
||||
}
|
||||
|
||||
if (this._parent && !opts.onlySelf) {
|
||||
this._parent.markAsPending({...opts, sourceControl});
|
||||
if (!opts.onlySelf) {
|
||||
this._parent?.markAsPending({...opts, sourceControl});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1321,12 +1321,12 @@ export abstract class AbstractControl<
|
||||
opts: {onlySelf?: boolean; emitEvent?: boolean; skipPristineCheck?: boolean},
|
||||
sourceControl: AbstractControl,
|
||||
): void {
|
||||
if (this._parent && !opts.onlySelf) {
|
||||
this._parent.updateValueAndValidity(opts);
|
||||
if (!opts.onlySelf) {
|
||||
this._parent?.updateValueAndValidity(opts);
|
||||
if (!opts.skipPristineCheck) {
|
||||
this._parent._updatePristine({}, sourceControl);
|
||||
this._parent?._updatePristine({}, sourceControl);
|
||||
}
|
||||
this._parent._updateTouched({}, sourceControl);
|
||||
this._parent?._updateTouched({}, sourceControl);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1415,8 +1415,8 @@ export abstract class AbstractControl<
|
||||
(this.statusChanges as EventEmitter<FormControlStatus>).emit(this.status);
|
||||
}
|
||||
|
||||
if (this._parent && !opts.onlySelf) {
|
||||
this._parent.updateValueAndValidity({...opts, sourceControl});
|
||||
if (!opts.onlySelf) {
|
||||
this._parent?.updateValueAndValidity({...opts, sourceControl});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1604,7 +1604,7 @@ export abstract class AbstractControl<
|
||||
*/
|
||||
getError(errorCode: string, path?: Array<string | number> | string): any {
|
||||
const control = path ? this.get(path) : this;
|
||||
return control && control.errors ? control.errors[errorCode] : null;
|
||||
return control?.errors ? control.errors[errorCode] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1729,8 +1729,8 @@ export abstract class AbstractControl<
|
||||
const changed = this.pristine !== newPristine;
|
||||
this.pristine = newPristine;
|
||||
|
||||
if (this._parent && !opts.onlySelf) {
|
||||
this._parent._updatePristine(opts, changedControl);
|
||||
if (!opts.onlySelf) {
|
||||
this._parent?._updatePristine(opts, changedControl);
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
@@ -1743,8 +1743,8 @@ export abstract class AbstractControl<
|
||||
this.touched = this._anyControlsTouched();
|
||||
this._events.next(new TouchedChangeEvent(this.touched, changedControl));
|
||||
|
||||
if (this._parent && !opts.onlySelf) {
|
||||
this._parent._updateTouched(opts, changedControl);
|
||||
if (!opts.onlySelf) {
|
||||
this._parent?._updateTouched(opts, changedControl);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1768,8 +1768,7 @@ export abstract class AbstractControl<
|
||||
* @internal
|
||||
*/
|
||||
private _parentMarkedDirty(onlySelf?: boolean): boolean {
|
||||
const parentDirty = this._parent && this._parent.dirty;
|
||||
return !onlySelf && !!parentDirty && !this._parent!._anyControlsDirty();
|
||||
return !onlySelf && !!this._parent?.dirty && !this._parent!._anyControlsDirty();
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
|
||||
Reference in New Issue
Block a user