15

I import a modal library of ng-bootstrap in a lazy module.

@NgModule({imports: [NgbModalModule]})

This library has a NgbModal service provided in root.

@Injectable({providedIn: 'root'})
class NgbModal {...}

I inject it into a component.

constructor(private modal: NgbModal) {}

I develop a class extension of that one.

export class CustomNgbModal extends NgbModal{...}

How can I override NgbModal type with CustomNgbModal?

Using modules will be

{provide: NgbModal, useClass: CustomNgbModal}

but using providedIn root metadata, no clue.

So, how can I override a module which is provided in root?

Serginho
  • 7,291
  • 2
  • 27
  • 52
  • do you want to make library think it is using CustomNgbModal and your code using it as CustomNgbModal? – Andrei Jan 29 '20 at 16:39
  • @Andrei I've injected NgbModal in a lot of componentes in my app. I want replace this type with my custom type. Like `{provide: NgbModal, useClass: CustomNgbModal}`but with modules provided in root. – Serginho Jan 29 '20 at 16:49

3 Answers3

1

create some static function forFeature() (like "useCustom")

@NgModule({
  // the default provider
  providers: [NgbModal]
})
export class NgbModalModule {
  static useCustom(): ModuleWithProviders<NgbModalModule> {
    return {
      ngModule: NgbModalModule,
      providers: [
        {provide: NgbModal, useClass: CustomNgbModal}
      ]
    };
  }
}

then when importing this module to another do it this way:

@NgModule({
  // import it using the static function
  imports: [NgbModalModule.useCustom()]
})
export class AnotherModule { }
David Lopes
  • 227
  • 2
  • 10
1

You can just specify provider on some level and it will be available to all components/modules down the hierarchy. root is NOT your main module but "above it" so you can override it as any other provider

Example stackblitz

@Injectable({providedIn:'root'})
export class BaseServiceService {
  constructor() { }
  sayHello(){
    console.log("Hello from the base!!!")
  }
}

@Injectable()
export class ExtendedServiceService extends BaseServiceService {
  constructor() {
    super();
   }
   sayHello(){
     console.log("Hello EXTENSION")
   }
}

@NgModule({
  imports:      [ BrowserModule, FormsModule ],
  declarations: [ AppComponent, HelloComponent ],
  providers:[
    {provide:BaseServiceService, useClass:ExtendedServiceService}
  ],
  bootstrap:    [ AppComponent ]
})
export class AppModule { }


export class AppComponent  implements OnInit{
  constructor(private s:BaseServiceService){}
ngOnInit(): void {
  this.s.sayHello();
}
}

Which results in

Hello EXTENSION

which means that you have effectively overriden 3rd party service provided in 'root' for the whole application. The same applies to any of your modules (no matter lazy or not).

Antoniossss
  • 31,590
  • 6
  • 57
  • 99
-3

I beleieve what you are trying to achieve can be done with

//module
providers: [
  CustomNgbModal, // so you can inject your custom service
  {provide: NgbModal, useExisting: CustomNgbModal} // to the library would use this service instead of its own
]
Andrei
  • 10,117
  • 13
  • 21
  • Did you read the chunk "Using modules will be{provide: NgbModal, useClass: CustomNgbModal}"? I know how to override a provider which is defined in the module. The question is: How to override a provider which is defined with @Injectable({providedIn: root})? – Serginho Jan 29 '20 at 16:47