Error using native lazy loaded component

I moved Camera from app.module to avatar-change.module:

import { NgModule } from '@angular/core';
import { IonicModule } from 'ionic-angular';
import { Camera } from "@ionic-native/camera";
import { AvatarChangeComponent } from './avatar-change';
import { SharedModule } from "../../shared/shared.module";
import { ImageUploadProviderModule } from "../../services/image-upload/image-upload.module";

@NgModule({
  declarations: [AvatarChangeComponent],
  imports: [
    IonicModule,
    SharedModule,
    ImageUploadProviderModule
  ],
  exports: [AvatarChangeComponent],
  entryComponents: [AvatarChangeComponent],
  providers: [Camera] // <-- here
})

export class AvatarChangeComponentModule {
}

I use this on a service like this:

import { Camera, CameraOptions } from "@ionic-native/camera";
...
constructor(private camera: Camera) {}

But get this error:

Uncaught (in promise): Error: StaticInjectorError(AppModule)[ImageUploadProvider -> Camera]:
StaticInjectorError(Platform: core)[ImageUploadProvider -> Camera]:
NullInjectorError: No provider for Camera!

I’m using also a different native component on a similar way (component and provider) and that one works ok

According to your error message, ImageUploadProvider is now sad because its friend Camera has moved to a new city and can no longer remain in touch.

Hi,

The camara provider needs to be registered in your main module.

but they keep talking to each other through their common friend avatar-change.module, right? (I forgot to add the line)

I have exactly the same thing with a different component, provider and native component and it’s in the same way

yes, forgot it. Added to avatar-change.module (but it still failing)

That would depend on whether ImageUploadProviderModule is importing AvatarChangeComponentModule or not. Leaving the current issue aside, simply based off the naming, I would consider it a red flag to have service provider modules importing component modules. I always want that relationship to be one-way. Components make use of providers. Providers make use of other providers, but never of components. So perhaps AvatarChangeComponentModule isn’t really where Camera should be living, for the overall cleanliness of the app.

@rapropos just some points:

  • ImageUploadProviderModule is only imported in avatar-change.module
  • Camera is imported by avatar-change.module but it’s being used inside ImageUploadProvider (which is where it’s failing) but not inside ImageUploadProviderModule

So your idea idea is move this function from ImageUploadProvider to avatar-change?

cropPicture(opts) {
    const options: CameraOptions = opts;
    this.camera.getPicture(options).then(
      imageData => {
        this.uploadingAvatarImg = "data:image/jpeg;base64," + imageData;
        this.events.publish("image:selected");
      },
      err => {
        // Handle error
      }
    );
  }

and change this line:
this.uploadingAvatarImg = "data:image/jpeg;base64," + imageData;
to this:
this.imageUploadProvider.uploadingAvatarImg = "data:image/jpeg;base64," + imageData;

Is that correct?

If so I’d also have to change the same thing with my SocialLoginProvider which uses Facebook and Google logins and move it to its component (login-buttons). But this one works ok

I thinks that put the ionic providers in modules is a bad choice, you will ends with a dependency mess.

You need to put the ionic providers in the app.module. Only put the providers in modules if they are yours.

This is the way to use lazy loading. The mess comes with the other way around, having everything on app.module.
This is the best way to scale medium/big apps

If you put your ionic native providers in the app.module everything is going to be more easy, with no dependency problems. The ionic native do not belong to any module.

With large applications it is difficult to work with strong dependencies, you will have many problems. I have worked in large applications and it is my advice.

@AxelStone again that’s not a lazy loading approach. You don’t need to load something that you won’t need on you app module. With a small app it’s ok but if you have 200 components you will load all of them, which is not ideal because maybe you just want to use 5.

Have a look to https://angular.io/guide/lazy-loading-ngmodules or to https://www.joshmorony.com/what-does-lazy-loading-do-in-ionic/

I thinks that components are different things that ionic native providers, but you are free. Good luck!

a component is a piece of code that you might use on a different part of your app. The logic here with lazy loading doesn’t change (at least as far as I know)

It’s only one possibility, but I like it because it gets UI stuff out of providers. I like keeping providers faceless, only dealing with network and other data-slinging. The ultimate problem is that Camera needs to be visible in the module scope of whatever class is trying to inject it.

Makes sense, but what happens if we need to call the Camera component function from another component which is not avatar-change? Would we have to repeat this function again?

If I import Camera from avatar-change it should work but as I said before I also open the camera from different components/pages so this provider is a global place to put this.

Should I create a new component just with this Camera component imported?

I would consider this a compelling argument for providing Camera in the app module.

Hi, you can also import the provider camera in the pages modules that uses it.

but what I mean is when we need a main function for the camera. For example, we use avatar-change when we have the classic “Update your avatar” option, but now, we need another function to take a picture like new-post which also uses the camera with similar camera options.

So now we have similar but different components.

Where should I place my this.camera.getPicture(options)? Should I have one function on each component?

That’s why I created here ImageUploadProvider, to have this function shared through my different camera component.

In that case you’ll declare the both providers in each page module that uses it.

we’ll get the same issue anyway.

We have:

  • component A
  • component B
  • page 1
  • page 2

On page 1 we want to take a picture and upload it and on page 2 we want to take another picture and edit it.

We have now the same function: takePicture(). Where should we put this function if we can’t import Camera inside a provider? Should we duplicate this function?