question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

DI problem with standalone component

See original GitHub issue

Which @angular/* package(s) are the source of the bug?

common

Is this a regression?

Yes

Description

I have a standalone component AppComponent and a module GuideModule and use createApplication() and @angular/elements to create custom element. I got an error when angular instantiate GuideListComponent (.in GuideModule ). Why it happens, I imported MatDialogModule in GuideModule.

AppComponent* @Component({ standalone: true, selector: 'pz-creator-app', templateUrl: './app.component.html', styleUrls: ['./app.component.scss'], encapsulation: ViewEncapsulation.ShadowDom, imports: [ CommonModule, // Features GuideModule, RouterModule, ], }) export class AppComponent implements OnDestroy {

GuideModule @NgModule({ declarations: [ GuideListComponent, GuideEditorComponent, SettingsDialogComponent, ], imports: [ MatDialogModule, ], schemas: [CUSTOM_ELEMENTS_SCHEMA], exports: [], }) export class GuideModule {}

main.ts createApplication({ providers: [ INTERCEPTORS, GLOBAL_CONFIG, importProvidersFrom([ HttpClientModule, MatSnackBarModule, AppRoutingModule, BrowserModule, BrowserAnimationsModule, CampaignDataAccessModule.forRoot(), ]), ], }).then((appRef) => { const ElementConstructor = createCustomElement(AppComponent, { injector: appRef.injector, }); customElements.define('pz-creator-app', ElementConstructor); });

Please provide a link to a minimal reproduction of the bug

No response

Please provide the exception or error you saw

`
ERROR Error: Uncaught (in promise): NullInjectorError: R3InjectorError(Environment Injector)[MatDialog -> MatDialog]: 
  NullInjectorError: No provider for MatDialog!
NullInjectorError: R3InjectorError(Environment Injector)[MatDialog -> MatDialog]: 
  NullInjectorError: No provider for MatDialog!
    at NullInjector.get (main.js:164607:21)
    at R3Injector.get (main.js:165110:27)
    at R3Injector.get (main.js:165110:27)
    at ChainedInjector.get (main.js:173498:32)
    at lookupTokenUsingModuleInjector (main.js:161055:31)
    at getOrCreateInjectable (main.js:161107:10)
    at Module.ɵɵdirectiveInject (main.js:169929:10)
    at NodeInjectorFactory.GuideListComponent_Factory [as factory] (main.js:872:559)
    at getNodeInjectable (main.js:161318:38)
    at instantiateRootComponent (main.js:172027:21)
    at resolvePromise (polyfills.js:1438:19)
    at resolvePromise (polyfills.js:1385:9)
    at polyfills.js:1512:9
    at ZoneDelegate.invokeTask (polyfills.js:459:171)
    at Object.onInvokeTask (main.js:187695:25)
    at ZoneDelegate.invokeTask (polyfills.js:459:54)
    at Zone.runTask (polyfills.js:220:37)
    at drainMicroTaskQueue (polyfills.js:664:23)
`

Please provide the environment you discovered this bug in (run ng version)

Angular CLI: 14.2.2
Node: 18.3.0 (Unsupported)
Package Manager: npm 8.11.0 
OS: darwin x64

Angular: 14.2.1
... animations, cdk, common, compiler, compiler-cli, core
... elements, forms, language-service, material
... platform-browser, platform-browser-dynamic, router
... service-worker

Package                         Version
---------------------------------------------------------
@angular-devkit/architect       0.1402.2
@angular-devkit/build-angular   14.2.2
@angular-devkit/core            14.2.2
@angular-devkit/schematics      14.2.2
@angular/cli                    14.2.2
@angular/flex-layout            14.0.0-beta.40
@schematics/angular             14.2.2
rxjs                            7.5.4
typescript                      4.7.3

Anything else?

For a workaround, it works when I extract providers of GuideModule and add them to createApplication()

main.ts createApplication({ providers: [ INTERCEPTORS, GLOBAL_CONFIG, importProvidersFrom([ ... GuideModule, ]), ], }).then((appRef) => { const ElementConstructor = createCustomElement(AppComponent, { injector: appRef.injector, }); customElements.define('pz-creator-app', ElementConstructor); });

Stackblitz

reproduce

Issue Analytics

  • State:closed
  • Created a year ago
  • Comments:6 (3 by maintainers)

github_iconTop GitHub Comments

1reaction
JoostKcommented, Oct 5, 2022

@pkozlowski-opensource and myself looked into this again today, and we’ve come to the conclusion that this is working as designed (although confusing).

What happens is that the <router-outlet> creates the routed component GuideListComponent in the context of the environment injector of the RouterModule, which is the root injector that is created using createApplication. GuideListComponent is not itself a standalone component, so there is no guarantee that the providers from its NgModule graph are present as would be the case with standalone components (standalone components were specifically designed to avoid this pitfall).

The injector that actually contains a provider for MatDialog is the standalone injector of AppComponent, but as previously mentioned the router uses its own environment injector, which is the root environment. Therefore, the standalone injector of AppComponent is not visible to the routed component instance.

One solution could be to make GuideListComponent itself standalone, and importing MatDialogModule from its `import array.

We do recognize that this behavior can be confusing and is not ideal, but using standalone components across the board aims to avoid cases like these. In a hybrid setup like the reproduction, the interaction between the various DI hierarchies becomes hard to reason about.

0reactions
angular-automatic-lock-bot[bot]commented, Nov 19, 2022

This issue has been automatically locked due to inactivity. Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

Read more comments on GitHub >

github_iconTop Results From Across the Web

DI problem with standalone component (forked) - StackBlitz
A angular-cli project based on @angular/animations, @angular/compiler, @angular/core, @angular/common, @angular/platform-browser-dynamic, @angular/forms, ...
Read more >
Getting started with standalone components - Angular
Standalone components provide a simplified way to build Angular applications. Standalone components, directives, and pipes aim to streamline the authoring ...
Read more >
The future of standalone components in the post-Ivy release ...
Modules have Injectors, providers, DI and many more than just a simple component. NgModules are kind of representing applications. And my point ...
Read more >
how are standalone components implemented under the hood?
Standalone components don't act as their own NgModules in the sense that importing them does NOT add providers to injectors, in the same...
Read more >
Error when trying to load a "standalone" component from a ...
I want to inject new standalone component CrashReportsComponent into my project. But I get an error when I try to connect a component...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found