components icon indicating copy to clipboard operation
components copied to clipboard

bug(Dialog): Explicit injector does not work

Open adzhiljano opened this issue 2 years ago • 8 comments

Is this a regression?

  • [ ] Yes, this behavior used to work in the previous version

The previous version in which this bug was not present was

No response

Description

Hey, I recently updated to v14 just for the newly added feature of the Dialog - the explicit injector, but it does not seem to work. I might be doing something wrong or misunderstood the new feature (to provide an Injector without having to provide a ViewContainerRef).

Reproduction

Steps to reproduce: Check out https://stackblitz.com/edit/angular-ozdqwy?file=src%2Fapp%2Fdialog-overview-example.ts (hope this lives long enough) OR

  1. Open the dialog example https://stackblitz.com/run?file=src/app/dialog-overview-example.ts
  2. Add some service @Injectable() export class SomeService { test = 123; }
  3. Create an injector const myInjector = Injector.create({ providers: [{ provide: SomeService }] });
  4. Pass the injector injector: myInjector`` to ``this.dialog.open
  5. Require the service public someService: SomeService in DialogOverviewExampleDialog's constructor

Expected Behavior

SomeService gets provided to DialogOverviewExampleDialog

Actual Behavior

ERROR NullInjectorError: R3InjectorError(AppModule)[SomeService -> SomeService -> SomeService]: 
  NullInjectorError: No provider for SomeService!
    at NullInjector.get (vendor.js:66456:21)
    at R3Injector.get (vendor.js:66652:27)
    at R3Injector.get (vendor.js:66652:27)
    at R3Injector.get (vendor.js:66652:27)
    at NgModuleRef.get (vendor.js:81766:29)
    at ChainedInjector.get (vendor.js:81534:32)
    at lookupTokenUsingModuleInjector (vendor.js:59680:31)
    at getOrCreateInjectable (vendor.js:59732:10)
    at Module.ɵɵdirectiveInject (vendor.js:67961:10)
    at NodeInjectorFactory.DialogOverviewExampleDialog_Factory [as factory] (main.js:153:195)

Environment

Angular CLI: 14.0.5 Angular: 14.0.5 Angular Material: 14.0.4
Node: 16.13.0 Package Manager: npm 8.1.0 OS: win32 x64

Additional info

I glanced into the source code and I think the injector from the config is taken into account only when creating/attaching the container: https://github.com/angular/components/blob/c28bbdeb51c31cbd1f5e06528ef4d21b1650e4a8/src/cdk/dialog/dialog.ts#L224 but not when creating/attaching the actual content component: https://github.com/angular/components/blob/c28bbdeb51c31cbd1f5e06528ef4d21b1650e4a8/src/cdk/dialog/dialog.ts#L311 and it seems that from a DI point of view, the implementation does not tie the content's Injector with the container's Injector. Again, I might be wrong.

Thanks!

adzhiljano avatar Jul 12 '22 15:07 adzhiljano

I have experienced the same, I've ended up needing to build components that (in a minor way) duplicate logic in order to specify providers instead of being able to pass up an injector.

BenjaminHutchinson avatar Aug 11 '22 06:08 BenjaminHutchinson

I have the same issue, the MatDialog implementation seems to work fine though, but the CDK dialog is unable to resolve the custom dependencies.

mpo-dev avatar Aug 29 '22 09:08 mpo-dev

Hey @mpo-dev , that is wierd. The example I posted in the Reproduction section uses the MatDialog . AFAIR MatDialog is just a thin wrapper around the cdk's Dialog and this issue should concern both of them.

adzhiljano avatar Aug 30 '22 13:08 adzhiljano

@adzhiljano In my production code I had the situation where opening a custom component in a dialog with MatDialog would work fine, but opening the same component in a dialog with Dialog would result in one of the custom components dependencies not being resolvable. I need the CDK Dialog because of the custom dialog container.

mpo-dev avatar Aug 31 '22 07:08 mpo-dev

Hello! Have the same issue on our project with MatDialog. Can not divide application to modules, viewContainerRef doesn't work as well. Services, that are injected only to the lazy-loaded module can not be accessible from the Dialog.

LeraAl avatar Feb 09 '23 15:02 LeraAl

It seems I found the root cause of the problem.

Component is created with deprecated API. So, it used the deprecated version of createComponent method with componentFactoryResolver. https://github.com/angular/components/blob/main/src/cdk/portal/portal-directives.ts#L155

As a result, component is created with componentFactoryResolver connected to the AppModule if it's not explicitly provided. Is it possible to fix the issue?

LeraAl avatar Feb 09 '23 16:02 LeraAl

I am also receiving this error using MatDialog on Angular 15.2.5

yharaskrik avatar May 04 '23 16:05 yharaskrik

We are experiencing the same issue. Instead of providing only injector we are forced to provide also deprecated component factory resolver to instantiate it in the correct dependency injection context

 this.matDialog.open(DialogComp, {
    injector: this.cmpInjector,
    componentFactoryResolver: this.cmpInjector.get(ComponentFactoryResolver),
  })

VeselyT avatar Feb 26 '24 13:02 VeselyT

@VeselyT's solution worked for me. I am trying to utilize a service to handle dialogs. Passing the "viewContainerRef" argument wasn't working, but once I used the componentFactoryResolver like VesleyT, it worked. The viewContainerRef option (or the injector option), are not passing the dependencies properly, as noted by others on this issue.

tonyholt avatar Mar 13 '24 02:03 tonyholt

Having the same issue. I think the problem is in the ComponentPortal. I'm generating the dialog myself using portals and I'm experiencing the exact same behavior described by others.

Angular Version 17.2.3

rojasjandro89 avatar Apr 11 '24 02:04 rojasjandro89