Eng
Eng

Reputation: 43

ionic3/angular 4 : Injecting a service in another service not working

I am trying to make a simple use of a service within another service (not into a Component) with Dependency Injection in ionic3/angular4. I thought I had understood how to do it in theory, but in practise I have been struglying several days...

Here is my configuration :

cli packages:
    @ionic/cli-plugin-ionic-angular : 1.4.1
    @ionic/cli-utils                : 1.7.0
    ionic (Ionic CLI)               : 3.7.0
local packages:
    @ionic/app-scripts : 2.1.3
    Ionic Framework    : ionic-angular 3.6.0

and this is my tsconfig.json file (as I have gone throught some threads suggesting compiling options could have some effects on injection behavior)

{
  "compilerOptions": {
    "allowSyntheticDefaultImports": true,
    "declaration": false,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "lib": [
      "dom",
      "es2015"
    ],
    "module": "es2015",
    "moduleResolution": "node",
    "sourceMap": true,
    "target": "es5"
  },
  "include": [
    "src/**/*.ts"
  ],
  "exclude": [
    "node_modules"
  ],
  "compileOnSave": false,
  "atom": {
    "rewriteTsconfig": false
  }
}

In my app.module.ts, I have registered some Services by importing their associated modules : NgLoggerModule & IonicStorageModule, others by adding them to providers array : SettingsStorageProvider & TMDbApiProvider :

@NgModule({
....
imports: [
    IonicStorageModule.forRoot(),
    NgLoggerModule.forRoot(Level.LOG)
],
providers: [
    ....
    SettingsStorageProvider,
    TMDbApiProvider
]

This is my SettingsStorageProvider class where I can make use of storage & logger services without problem :

@Injectable()
export class SettingsStorageProvider {

    constructor(public storage: Storage, public logger: Logger) {
        this.logger.log('Hello SettingsStorageProvider');
    }

    public saveSettings(_settings: SettingsModel){
    .... }

    public loadSettings(): Promise<SettingsModel> {
    ....}
}

This is my TMDbApiProvider class where I cannot make use of injected services Logger or SettingsStorageProvider even thought they seem to be correctly registered in app.module.ts :

@Injectable()
export class TMDbApiProvider {

static get parameters() {
    return [[Http]];
}
    constructor(public settingsStorage: SettingsStorageProvider, public http: Http, 
    public logger: Logger) {
     if (settingsStorage == null)
         console.log('TMDbApiProvider:constructor-->settingsStorage is NULL !!!');
     if (logger  == null)
         console.log('TMDbApiProvider:constructor-->logger is NULL !!!');
     if (http == null)
         console.log('TMDbApiProvider:constructor-->http is NULL !!!');
}

    searchMovies(movieName) {
        this.settingsStorage.loadSettings().then((_settings) => {
        .....
            var url = Config.data.tmdb_searchService + encodeURI(movieName) + '&'+Config.data.tmdb_apiKey+'&'+Config.data.tmdb_language+_userSettings.getLanguage();
            var response = this.http.get(url).map(res => res.json());

            return response;
        });
    }
}

I have no errors at compile time, but at runtime, I got the following debug logs I have put in the constructor :

tmdb-api.ts:30 TMDbApiProvider:constructor-->logger is NULL !!!

tmdb-api.ts:34 TMDbApiProvider:constructor-->http is NULL !!!

and the following error :

ERROR Error: Uncaught (in promise): TypeError: _this.settingsStorage.loadSettings is not a function
TypeError: _this.settingsStorage.loadSettings is not a function
    at tmdb-api.ts:48
    at new t (polyfills.js:3)
    at TMDbApiProvider.webpackJsonp.171.TMDbApiProvider.searchMovies

If I invert the order of the injected services in the constructor :

@Injectable()
export class TMDbApiProvider {

    constructor(public http: Http, public logger: Logger,
    public settingsStorage: SettingsStorageProvider) {

I got different debug logs I have put in the constructor :

TMDbApiProvider:constructor-->settingsStorage is NULL !!! tmdb-api.ts:31 TMDbApiProvider:constructor-->logger is NULL !!!

and the error has also changed :

ERROR Error: Uncaught (in promise): TypeError: Cannot read property 'loadSettings' of undefined
TypeError: Cannot read property 'loadSettings' of undefined

It seems that only the first service called into TMDbApiProvider constructor is injected.

Anyone has ever faced this strange behavior ? Thank you in advance for any help you could provide to me.

[15/08/2017] Here is a complementary information for my problem:

The root "NgModule" with the "declarations", "imports", "entryComponents" & "providers" of myApp : NgModule and a view of the injector graph of myApp using "Augury" Chrome Extension : Injector Graph

Strangely, "TMDbAPIProvider" declared as a Provider in root "NgModule" is not part of the injector graph... Do someone know why this could be ? Thank you in advance for your help (it's driving me nuts !).

enter image description here

Upvotes: 2

Views: 1752

Answers (1)

Sampath
Sampath

Reputation: 65870

Yes, You must remove the static keyword on parameters() method if you need to use that service through DI.That is by design.But if you need to use Static methods then you don't need to instantiate that class through DI.You can use it like below when you need it on the component:

import { TMDbApiProvider } from './TMDbApiProvider';

export class YourComponent {

    constructor() {
        // This is just an example of accessing the static members of a class.
        // Note: we didn't inject the service, nor manually instantiate it 
        let value = TMDbApiProvider.parameters();
     }
  }

Upvotes: 1

Related Questions