accessing component functions in shared modules

564 views Asked by At

I have a shared module that contains common components such as headers and notification components. I have a another module called ProductModule which uses the notification component from the shared module and calls a function defined in the notification component.

shared.module.ts

@NgModule({
    declarations: [
        HeaderComponent,
        SideNavComponent,
        SpinnerComponent,
        ItemSummaryComponent,
        UserRoleDirective,
        EmptyResultComponent,
        NotificationComponent
    ],
    imports: [
        CommonModule,
        RouterModule,
        MatProgressSpinnerModule,
        MatIconModule
    ],
    exports: [
        HeaderComponent,
        SideNavComponent,
        SpinnerComponent,
        ItemSummaryComponent,
        EmptyResultComponent,
        NotificationComponent
    ],
})
export class SharedModule {}

notification.component.ts

export class NotificationComponent {
  openSnackBar(message: string, state: string, icon: string): void {
    const config = new MatSnackBarConfig();
    config.duration = 3000;
    config.panelClass = ['nc-notification', state];
    config.data = { message, icon };
    this._snackBar.openFromComponent(NotificationComponent, config);
  }
}

In my lazy loaded productModuel, I have imported my sharedModule as below.

import { CommonCmpsModule } from '../common-cmps/common-cmps.module';
import { TaxConfigurationComponent } from './tax-configuration/tax-configuration.component';

    @NgModule({
      declarations: [
        TaxConfigurationComponent
      ],
      imports: [
        SharedModule,
      ]
    })
    export class ProductModule { }

In my TaxConfigurationComponent, I want to use the notification component and call the openSnackBar function.

TaxConfiguration.component.ts

import { NotificationComponent } from 'src/app/common-cmps/notification/notification.component';

export class TaxConfigurationComponent {
    constructor(
        private notificationService: NotificationService
    ){}

    onClickSave(): void {
        this.notificationService.openSnackBar('An Error Occurred', 'nc-notification--error', 'close');
    }
}

But, I'm getting below error in the browser console.

ERROR Error: Uncaught (in promise): NullInjectorError: R3InjectorError(ProductManagementModule)[NotificationComponent -> NotificationComponent -> NotificationComponent -> NotificationComponent]: NullInjectorError: No provider for NotificationComponent!

3

There are 3 answers

0
Aakash Garg On

constructor is used for injecting services not component.

For a component there are two options you have.

  1. if selector is used, you can use @ViewChild to get notification component instance and call the method.

  2. if selector is not used, create a service with a subject and call .next on that subject from taxconfiguration component. subscribe that subject in notification component and call your opensnackbar method inside subscribe.

1
PushpikaWan On

Do not use constructor injection for the component. In tax configuration component you are using

 constructor(
        private notificationCmp: NotificationComponent
    ){}

please remove that. And inject MatSnackBar service which is provided by material like below

import {MatSnackBar} from '@angular/material/snack-bar';
constructor(private _snackBar: MatSnackBar) {}

this and use your custom component like below

  this._snackBar.openFromComponent(NotificationComponent, {
      duration: 1500,
    });

Other than that u need to add NotificationComponent as an entry component inside the model

  entryComponents: [NotificationComponent],
0
dev_ob On

Could the issue be that you are importing NotificationComponent but in constructor you are referencing NotificationService and trying to call the function defined in NotificationComponent ?