Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I pass an argument to a provider constructor in Ionic2 / Angular2?

I am trying to port my Ionic2.beta11 App to the new Ionic2.rc0 release. Most things were pretty straight forward, but I have a problem with the AoT compiler.

I have an AuthService:

@Injectable()
export class AuthService {
  constructor(@Inject(Http) http: Http) {
    this.http = http;
  }
  ...
}

I'm injecting it into my app in the src/app/app.module.ts file:

@NgModule({
  declarations: [
    MyApp,
    ...
  ],
  imports: [
    IonicModule.forRoot(MyApp)
  ],
  bootstrap: [IonicApp],
  entryComponents: [
    MyApp,
    ...
  ],
  providers: [
    AuthService
  ]
})

Everything works fine when running ionic serve, but when I try to build it I get the following error:

ngc error: Error: Error at .../.tmp/app/app.module.ngfactory.ts:397:78: Supplied parameters do not match any signature of call target.

Lines 396 - 399:

get _AuthService_74():import44.AuthService {
  if ((this.__AuthService_74 == (null as any))) { (this.__AuthService_74 = new import44.AuthService()); }
  return this.__AuthService_74;
}

The problem is that new import44.AuthService() expects an argument of type http.

The interesting thing is that everything works fine when I manually replace constructor(http: Http) with constructor() in the definition file.

I read through all the StackOverflow answers I could find, but none of the solutions solved my problem.

Do I need to change the constructor in the AuthService or the way how I inject it into my app? Thank you for your help.

like image 548
Andreas Gassmann Avatar asked Oct 03 '16 10:10

Andreas Gassmann


2 Answers

I had the same issue & Markus put me on the right track but here's what I needed to do to get going (see also "Factory Providers" under Angular docs Dependency Injection):

Make the constructor parameter in the injected service optional. This alone is not enough (http was undefined at runtime)

constructor(public http?: Http){}

Create a service provider class SomeServiceProvider.ts:

import { Http } from '@angular/http';
import { SomeService } from 'some-service';

export function someServiceFactory(http: Http){
  return new SomeService(http);
}

export let SomeServiceProvider =
  { provide: SomeService,
    useFactory: someServiceFactory,
    deps: [ Http ]
  };

In the root app.component.ts, add the service provider:

@Component({
  ...
  providers: [ SomeServiceProvider ]
})

Remove the service from the @NgModule providers in app.module.ts.

To use the service in components, get it from Injector rather than injecting the service:

import { Component, Injector } from '@angular/core';
import { SomeService } from 'some-service';

@Component({
  ...
})

export class MyComponent{
  someService: SomeService = this.injector.get(SomeService);

  constructor(private injector: Injector) {}

}
like image 183
planetClaire Avatar answered Nov 01 '22 13:11

planetClaire


You have to change the way, how you define the provider:

@NgModule({
  ...
  providers: [
    Http,
    {
      provide: AuthService,
      useFactory: getAuthService,
      deps: [Http]
    }
  ]
})

The last piece is the factory function:

export function getAuthService(http: Http): LoggingService {
  return new AuthService(http);
}

See also Migrating to Ionic 2 RC 0 - ngc fails

like image 11
Markus Wagner Avatar answered Nov 01 '22 12:11

Markus Wagner