5

I'm using an Angular plugin, which needs to be configured by providing a configuration object using an InjectionToken that the plugin exports.

import { pluginToken } from 'plugin';

@NgModule({
  providers: {
    // Configure the plugin
    //
    // The configuration value string needs to be taken from some other
    // provider (available for dependency injection).
    { provides: pluginToken, useValue: valueString },
  },
})
class MyModule {
  ...
}

The problem I have is that valueString is a value from some other provider. I don't know how to inject a dependency into @NgModule decorator's provider. How it can be done?

Robert Kusznier
  • 6,471
  • 9
  • 50
  • 71

2 Answers2

4

The problem I have is that valueString is a value from some other provider

You can forward the value of one provider to another using useExisting

@NgModule({
    providers: [
        {provide: LOCALE_ID, useValue: 'en'},
        {provide: pluginToken, useExisting: LOCALE_ID},
    ],
})
export class MyModule {}

In the above example 'en' will be assigned to pluginToken because it uses the existing value of LOCALE_ID

Reactgular
  • 52,335
  • 19
  • 158
  • 208
  • Exactly what I needed. Thanks :). BTW do you also have an idea how to handle the case, if I'd need to somehow transform the value? - not use identical one like in this case. – Robert Kusznier Aug 29 '18 at 15:00
  • 1
    @RobertKusznier I would use a factory provider which takes a function. The limitation is that a factory function doesn't have access to the injector to get other providers. That's why I asked if it was a HTTP request. As there are other hacks to get around the problem. – Reactgular Aug 29 '18 at 15:04
  • Some reference docs here: https://angular.io/guide/dependency-injection-in-action#useexistingthe-alias-provider – lealceldeiro Aug 29 '18 at 15:05
  • @cgTag True, to apply a function alone is easy indeed. But what about the case, if I'd need to actually inject some other provider to get that value (like make HTTP request per your example). Is that possible at all? – Robert Kusznier Aug 29 '18 at 15:11
  • 1
    @RobertKusznier you can but not with a module. You would create a component using a component factory, and create an injector that has the custom provider value in it. You would use that injector to create the component. That component and all of it's children would have access to this new provider. – Reactgular Aug 29 '18 at 17:18
  • @cgTag Pretty complicated, but I think I get the main idea. Thank you for all the explanations. – Robert Kusznier Aug 30 '18 at 09:35
1

Instead of useValue, inject the object instance by using useClass which

creates and returns new instance of the specified class


Code:

// ...
{ provides: pluginToken, useClass: YourConfigurationObjectClass },
//...
lealceldeiro
  • 14,342
  • 6
  • 49
  • 80
  • My mistake, as I didn't specify that the value actually needs to be a `string`, not an object. I corrected the question. Will your answer somehow handle providing a primitive value too? – Robert Kusznier Aug 29 '18 at 14:47
  • Do you mean `valueString` is a value you get using another provider's method (for example) and not using the provider instance itself? Do know if that makes sense (what I'm asking). I don't think I understand the scenario correctly. – lealceldeiro Aug 29 '18 at 14:55
  • To be precise `valueString` is a locale string available for injection under `LOCALE_ID` token from `@angular/core`. And it wasn't your fault you didn't understand the scenario, as I incorrectly stated at first that the value is an object, not a string. – Robert Kusznier Aug 29 '18 at 14:57