Zyga
Zyga

Reputation: 2417

Use ionic native service in Angular4 component

I am struggling to inject ionic-native Camera service into my custom component. I can inject and use it into the lazy loaded Ionic page (i.e. component with @IonicPage decorator) but when I try to create a separate component that uses this service, and use that component in the above page, the Camera service is always undefined.

I have tried many combinations within modules for both the page and the component to get it to work (as I believe its somehow related to module structure) but none of them worked for me. My latest code is below - the camera injected in the custom component ends up being 'undefined'.

Basically my goal is to have a stand alone module with set of components that use native ionic services and that can be reused across different modules/pages.

Module declaration for the HomePage:

@NgModule({
  declarations: [
    HomePage
  ],
  imports: [
    IonicPageModule.forChild(HomePage),
    IonicModule,
    SharedModule, //this is module with some shared stuff
    CustomModule
  ],
  providers: [
    Camera
  ]
})
export class HomePageModule {}

I can inject Camera service into the HomePage component below no problems:

@IonicPage()
@Component({
  selector: 'page-home',
  templateUrl: 'home.html',
})
export class HomePage {
  constructor(private camera: Camera) {}
}

My CustomModule is here:

@NgModule({
  declarations: [
    CustomComponent
  ],
  exports: [
    CustomComponent
  ],
  imports: [
    CommonModule,
    SharedModule,
    IonicModule.forRoot(CustomComponent)
  ],
  providers: [
    Camera
  ]
})
export class CustomModule {}

And my CustomComponent is here - camera variable is undefined.

@Component({
  selector: 'custom-component',
  template: '<p>test</p>'
})
export class CustomComponent {
  constructor(private camera: Camera) {}
}

Upvotes: 0

Views: 70

Answers (1)

Michael Kang
Michael Kang

Reputation: 52847

All services in a provider array of an NgModule are registered with the root injector. This injector is application-wide. Lazy-loaded NgModules create their own root scope, and its so its scope is limited to the lazy loaded module.

That is why, if you want to share services across the application, that you make sure to only register services with the root (app-wide) injector.

You can register services with the root injector by importing modules directly into AppModule, and using the forRoot convention. forRoot should be called in one place - the AppModule. Use forChild everywhere else.

I don't know too much about Ionic, but I think there are two issues here.

First, you need to import CustomModule by defining a static forRoot method, so that Camera can be registered with the root injector:

@NgModule({
  declarations: [
    HomePage
  ],
  imports: [
    IonicPageModule.forChild(HomePage),
    IonicModule,
    SharedModule, //this is module with some shared stuff
    CustomModule // without services
  ],
  providers: [
  ]
})
export class HomePageModule {}

And CustomModule:

@NgModule({
  declarations: [
    CustomComponent
  ],
  exports: [
    CustomComponent
  ],
  imports: [
    CommonModule,
    SharedModule,
    IonicModule.forChild(CustomComponent)      
  ],
  providers: [

  ]
})
export class CustomModule {
     static forRoot():ModuleWithProviders {
         return {
             ngModule: CustomModule, 
             providers: [Camera]
         }
     }
}

Second, forRoot() should always be registered with the AppModule. Anywhere else, you should import forChild() or just the module (without forRoot).

Upvotes: 2

Related Questions