Skip to content

Commit f093b20

Browse files
crisbetojosephperrott
authored andcommitted
fix(platform-browser): avoid circular DI error in async renderer
In angular/components#30179 the CDK overlay started depending on the `Renderer2Factory`. Since the overlay is used in the `MatSnackbar` which is commonly used in error handlers, `Overlay` can end up being injected as a part of the app initialization. Because `AsyncAnimationRendererFactory` depends on the `ChangeDetectionScheduler`, it may cause a circular dependency. These changes inject the `ChangeDetectionScheduler` lazily to avoid the error. Note: this will also be resolved by angular#58984, but I decided to send it out, because: 1. angular#58984 seems to be stuck on some internal cleanup. 2. The `AsyncAnimationRendererFactory` doesn't need the `scheduler` eagerly anyway so the change is fairly safe. Fixes angular#59255.
1 parent c73aee2 commit f093b20

File tree

2 files changed

+24
-1
lines changed

2 files changed

+24
-1
lines changed

packages/platform-browser/animations/async/src/async_animation_renderer.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ const ANIMATION_PREFIX = '@';
3434
@Injectable()
3535
export class AsyncAnimationRendererFactory implements OnDestroy, RendererFactory2 {
3636
private _rendererFactoryPromise: Promise<AnimationRendererFactory> | null = null;
37-
private readonly scheduler = inject(ChangeDetectionScheduler, {optional: true});
37+
private scheduler: ChangeDetectionScheduler | null = null;
38+
private readonly injector = inject(Injector);
3839
private readonly loadingSchedulerFn = inject(ɵASYNC_ANIMATION_LOADING_SCHEDULER_FN, {
3940
optional: true,
4041
});
@@ -143,6 +144,7 @@ export class AsyncAnimationRendererFactory implements OnDestroy, RendererFactory
143144
rendererType,
144145
);
145146
dynamicRenderer.use(animationRenderer);
147+
this.scheduler ??= this.injector.get(ChangeDetectionScheduler, null, {optional: true});
146148
this.scheduler?.notify(NotificationSource.AsyncAnimationsLoaded);
147149
})
148150
.catch((e) => {

packages/platform-browser/animations/async/test/animation_renderer_spec.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import {
2424
afterNextRender,
2525
ANIMATION_MODULE_TYPE,
2626
Component,
27+
ErrorHandler,
2728
inject,
2829
Injectable,
2930
Injector,
@@ -447,6 +448,26 @@ type AnimationBrowserModule = typeof import('@angular/animations/browser');
447448
}
448449
});
449450
});
451+
452+
it('should be able to inject the renderer factory in an ErrorHandler', async () => {
453+
@Injectable({providedIn: 'root'})
454+
class CustomErrorHandler {
455+
renderer = inject(RendererFactory2).createRenderer(null, null);
456+
}
457+
458+
@Component({template: ''})
459+
class App {}
460+
461+
TestBed.resetTestingModule();
462+
TestBed.configureTestingModule({
463+
providers: [
464+
provideAnimationsAsync(),
465+
{provide: ErrorHandler, useClass: CustomErrorHandler},
466+
],
467+
});
468+
469+
expect(() => TestBed.createComponent(App)).not.toThrow();
470+
});
450471
});
451472
})();
452473

0 commit comments

Comments
 (0)