Skip to content

Commit

Permalink
fix(angular): workaround for a bug in Angular when updating to v16.2.4
Browse files Browse the repository at this point in the history
  • Loading branch information
divdavem committed Sep 19, 2023
1 parent 140e979 commit b0d09e0
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 24 deletions.
46 changes: 27 additions & 19 deletions angular/headless/src/lib/use.directive.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@ import type {OnChanges, OnDestroy, SimpleChanges} from '@angular/core';
import {Directive, ElementRef, inject, Input} from '@angular/core';
import type {Directive as AgnosUIDirective} from '@agnos-ui/core';

// All calls of the directive in this class are done asynchronously (with await 0)
// in order to avoid ExpressionChangedAfterItHasBeenCheckedError
// or the corresponding issue with signals (https://github.com/angular/angular/issues/50320)
// This is relevant especially if calling the directive changes variables used in a template.

@Directive({
standalone: true,
selector: '[auUse]',
Expand All @@ -13,37 +18,40 @@ export class UseDirective<T> implements OnChanges, OnDestroy {
@Input('auUseParams')
params: T | undefined;

private _ref = inject(ElementRef);
#ref = inject(ElementRef);

#directive: AgnosUIDirective<T> | undefined;
#directiveInstance?: ReturnType<AgnosUIDirective<T>>;

private _directive: AgnosUIDirective<T> | undefined;
private _directiveInstance?: ReturnType<AgnosUIDirective<T>>;
async #destroyDirectiveInstance() {
const directiveInstance = this.#directiveInstance;
this.#directiveInstance = undefined;
if (directiveInstance?.destroy) {
await 0;
directiveInstance.destroy?.();
}
}

async ngOnChanges(changes: SimpleChanges): Promise<void> {
if (this.use !== this._directive) {
this._directiveInstance?.destroy?.();
this._directiveInstance = undefined;
if (this.use !== this.#directive) {
this.#destroyDirectiveInstance();
const directive = this.use;
this._directive = directive;
this.#directive = directive;
if (directive) {
// waiting here is necessary to avoid ExpressionChangedAfterItHasBeenCheckedError
// in case calling the directive changes variables used in the template
await Promise.resolve();
await 0;
// checks that the directive did not change while waiting:
if (directive === this._directive && !this._directiveInstance) {
this._directiveInstance = directive(this._ref.nativeElement, this.params as T);
if (directive === this.#directive && !this.#directiveInstance) {
this.#directiveInstance = directive(this.#ref.nativeElement, this.params as T);
}
}
} else if (changes['params']) {
// waiting here is necessary to avoid ExpressionChangedAfterItHasBeenCheckedError
// in case calling the directive changes variables used in the template
await Promise.resolve();
this._directiveInstance?.update?.(this.params as T);
await 0;
this.#directiveInstance?.update?.(this.params as T);
}
}

ngOnDestroy(): void {
this._directiveInstance?.destroy?.();
this._directiveInstance = undefined;
this._directive = undefined;
this.#destroyDirectiveInstance();
this.#directive = undefined;
}
}
5 changes: 0 additions & 5 deletions angular/lib/src/lib/modal/modal.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import {
Output,
TemplateRef,
ViewChild,
effect,
inject,
} from '@angular/core';
import {toSignal} from '@angular/core/rxjs-interop';
Expand Down Expand Up @@ -271,10 +270,6 @@ export class ModalComponent implements OnChanges, AfterContentChecked {
onBeforeClose: (event) => this.beforeClose.emit(event),
onVisibleChange: (event) => this.visibleChange.emit(event),
});
effect(() => {
// TODO: workaround to be removed when https://github.com/angular/angular/issues/50320 is fixed
this.state();
});
}

ngAfterContentChecked(): void {
Expand Down

0 comments on commit b0d09e0

Please sign in to comment.