ngxtension / ngxtension-platform

Utilities for Angular
https://ngxtension.netlify.app/
MIT License
591 stars 87 forks source link

why extraProviders doesn't accept service(provider)? #423

Open jon9090 opened 3 months ago

jon9090 commented 3 months ago

I want to pass a lazy component to the foo service as an option without making a direct call. I aim to achieve this using an injection token. Additionally, I want to ensure that the scope of foo is limited to the component instance. This way, I can pass both the injection token and foo to the component providers in the usual manner.

Since I'm using ngxtension, is it possible to provide both the injection token and the foo class in a single provide function?

the problem is in extraProviders:

const [injectFoo, provideFoo] = createNoopInjectionToken<{
  dialogComponent: () => Promise<Type<FooComponent>>;
}>('foo options', { extraProviders: [Foo] }); // <----

argument of type '{ extraProviders: (typeof Foo)[]; }' is not assignable to parameter of type 'Pick<CreateInjectionTokenOptions<() > => void, []>, "extraProviders"> & Record<string, never>'. Type '{ extraProviders: (typeof Foo)[]; }' is not assignable to type 'Record<string, never>'. Property 'extraProviders' is incompatible with index signature. Type '(typeof Foo)[]' is not assignable to type 'never

stackblitz demo

Here is the code:

import { Component, Injectable, Type } from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';
import 'zone.js';
import { createNoopInjectionToken } from 'ngxtension/create-injection-token';

@Component({
  standalone: true,
  template: 'I am foo',
})
export class FooComponent {}

const [injectFoo, provideFoo] = createNoopInjectionToken<{
  dialogComponent: () => Promise<Type<FooComponent>>;
}>('foo options', { extraProviders: [Foo] });

@Injectable({ providedIn: 'root' })
export class Foo {
  foo = injectFoo();

  async work() {
    const dialogComponent = await this.foo.dialogComponent();
    console.log({ dialogComponent });
  }
}

@Component({
  selector: 'app-root',
  standalone: true,
  template: `
    <h1>Hello from {{ name }}!</h1>
    <a target="_blank" href="https://angular.dev/overview">
      Learn more about Angular
    </a>
  `,
  providers: [
    provideFoo({
      dialogComponent: () => import('./main').then((m) => m.FooComponent),
    }),
  ],
})
export class App {
  name = 'Angular';
}

bootstrapApplication(App);
jon9090 commented 3 months ago

@eneajaho @nartc Is this something I'm unable to accomplish with the extension?