shlomiassaf/ngrid

In ngrid 5.0.0 resolving of PblNgridCellFactoryResolver fails in createComponent()

t00 opened this issue · 7 comments

t00 commented

After switching to Angular 14 and using ngrid 5.0.0 a new error appears which might be related to how ngrid registers it's dependencies.

In a modal service responsible for showing components of a given type, I create components using .viewContainerRef.createComponent() because angular obsoleted ComponentFactoryResolver. If such component contains ngrid, it crashes due to the following error:

ERROR NullInjectorError: R3InjectorError(AppModule)[PblNgridCellFactoryResolver -> PblNgridCellFactoryResolver -> PblNgridCellFactoryResolver]: 
  NullInjectorError: No provider for PblNgridCellFactoryResolver!
    at NullInjector.get (core.mjs:8191:27)
    at R3Injector.get (core.mjs:8618:33)
    at R3Injector.get (core.mjs:8618:33)
    at R3Injector.get (core.mjs:8618:33)
    at ChainedInjector.get (core.mjs:13811:36)
    at lookupTokenUsingModuleInjector (core.mjs:3293:39)
    at getOrCreateInjectable (core.mjs:3338:12)
    at NodeInjector.get (core.mjs:3603:16)
    at new InternalExtensionApi (pebula-ngrid.mjs:5851:45)
    at createApis (pebula-ngrid.mjs:5833:12)
    at new PblNgridComponent (pebula-ngrid.mjs:7536:24)
    at NodeInjectorFactory.PblNgridComponent_Factory [as factory] (pebula-ngrid.mjs:8017:42)
    at getNodeInjectable (core.mjs:3523:44)
    at instantiateAllDirectives (core.mjs:12731:27)
    at createDirectivesInstances (core.mjs:12155:5)
    at Module.ɵɵelementStart (core.mjs:15285:9)
    at MyComponent_Template (my.component.html:1:1)
    at executeTemplate (core.mjs:12126:9)

Line which triggers the error:

const cellFactory = tokens.injector.get(PblNgridCellFactoryResolver);

When ngrid is shown in a normally instantiated component, it works fine.

It might be that I might have to do something extra to make PblNgridCellFactoryResolver registration work although I don't know what would help or if there is exposed a default registration function.

t00 commented

I think I identified the problem. PblNgridCellFactoryResolver should be marked with @Injectable(providedIn: 'root') as this service seems to be use to handle customization of NGRID_CELL_FACTORY.

It might be limiting to have single root implementation of resolver but ngridCellFactory function still depends on legacy ComponentFactoryResolver so it needs to be changed anyway which gives an opportunity of handling an argument allowing to vary implementation based on module/grid/injector etc.

Unfortunately I am a bit stuck with 5.0.0 as I cannot find a way to re-register PblNgridCellFactoryResolver in root which implementation relying on injector demands. Maybe you have some ideas?

How about registering the PblNgridCellFactoryResolver directly in the AppModule? Would it solve?

@NgModule({
    declarations: [
        AppComponent
    ],
    imports: [
		...
    ],
    providers: [ PblNgridCellFactoryResolver ],  // <<<---
    bootstrap: [
        AppComponent
    ]
})
export class AppModule {}
t00 commented

I tried it already and it complains that module ngrid/lib is not exported.
Edit: my only workaround at the moment is to import PblNgrid* in app.module which increased app initial size by a few MB.

Would you have a project that reproduces this error to share?

As a workaround, maybe you could try passing the injector when creating the component, but I'm not sure it would work.

this.viewContainerRef.createComponent(AComponent, {injector: this.injector});
t00 commented

Here is a reproducible project: stackblitz.com

Clicking on a button will throw an error in a console.

I was trying to resolve this issue without changing ngrid.
One way to create the component is to make it a standalone component. ( https://stackblitz.com/edit/pebula-ngrid-starter-8cg3gh )
I hope someone suggests a better solution.

I found another solution based on this thread

Here is the solution Stackblitz