Использование MatSnackBar в библиотеке

У меня проблема с использованием MatSnackBar из библиотеки. Я создал простой компонент, который выглядит так:

      <div class="situ-error-snackbar">
    <span>{{message}}</span>
    <button type="button" mat-icon-button (click)="close()">
        <mat-icon>closer</mat-icon>
    </button>
</div>

Код просто выглядит так:

      import {
  Component,
  Inject,
  Input,
  OnInit,
  ViewEncapsulation,
} from '@angular/core';

import {
  MatSnackBarRef,
  MAT_SNACK_BAR_DATA,
} from '@angular/material/snack-bar';

@Component({
  selector: 'situ-error-snackbar',
  templateUrl: './error-snackbar.component.html',
  styleUrls: ['./error-snackbar.component.scss'],
  encapsulation: ViewEncapsulation.None,
})
export class ErrorSnackbarComponent implements OnInit {
  @Input() duration: number = 5000;

  public constructor(
    @Inject(MAT_SNACK_BAR_DATA) public message: string,
    public snackBarRef: MatSnackBarRef<ErrorSnackbarComponent>
  ) {}

  public ngOnInit(): void {}

  public close(): void {
    this.snackBarRef.dismiss();
  }
}

И у меня есть служба, которая вызывает его:

      public show(notifcation: Notification): void {
  let config: MatSnackBarConfig = {
    panelClass: notifcation.type,
    verticalPosition: 'top',
    duration: 5000,
    data: notifcation.message,
  };

  this.snackBar.openFromComponent(ErrorSnackbarComponent, config);
}

Все это находится в пользовательской библиотеке, которую я разрабатывал. Панель ошибок имеет модуль, который выглядит так:

      import { NgModule } from '@angular/core';

import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon';
import { MatSnackBarModule } from '@angular/material/snack-bar';

import { ErrorSnackbarComponent } from './error-snackbar.component';

@NgModule({
  imports: [MatButtonModule, MatIconModule, MatSnackBarModule],
  declarations: [ErrorSnackbarComponent],
  exports: [ErrorSnackbarComponent],
})
export class ErrorSnackbarModule {}

В моем приложении я хочу отображать ErrorSnackbar всякий раз, когда возникает ошибка, поэтому я добавил его в AppComponent следующим образом:

      <router-outlet></router-outlet>

<situ-error-snackbar></situ-error-snackbar>

И я импортирую библиотечный модуль в app.module следующим образом:

      @NgModule({
    declarations: [AppComponent],
    imports: [
        BrowserModule,
        BrowserAnimationsModule,
        HttpClientModule,
        CoreModule,
        AppRoutingModule,

        MatAutocompleteModule,
        MatDatepickerModule,
        MatNativeDateModule,
        MatSelectModule,

        ErrorSnackbarModule,
    ],
    providers: [
        { provide: HTTP_INTERCEPTORS, useClass: BearerAuthInterceptor, multi: true },
        { provide: HTTP_INTERCEPTORS, useClass: ErrorInterceptor, multi: true },
        { provide: MAT_DATE_LOCALE, useValue: 'en-GB' },
    ],
    bootstrap: [AppComponent],
})
export class AppModule {}

На мой взгляд, это должно просто работать. У меня есть много других компонентов в этой библиотеке, и все они работают нормально. Но когда я пытаюсь запустить свое приложение в указанном выше состоянии, я получаю эту ошибку:

ОШИБКА NullInjectorError: R3InjectorError(AppModule)[InjectionToken MatSnackBarData -> InjectionToken MatSnackBarData -> InjectionToken MatSnackBarData]:NullInjectorError: нет поставщика для InjectionToken MatSnackBarData!

Я погуглил ошибку и нашел что-то похожее здесь:https://github.com/angular/universal-starter/issues/493 .

Поэтому я сделал то, что они сказали, и добавил это в app.module:

      {
    provide: MAT_SNACK_BAR_DATA,
    useValue: {}, // Add any data you wish to test if it is passed/used correctly
},

Когда я это делаю, я получаю новую ошибку:

ОШИБКА NullInjectorError: R3InjectorError(AppModule)[MatSnackBarRef -> MatSnackBarRef -> MatSnackBarRef]:NullInjectorError: Нет поставщика для MatSnackBarRef!

Поэтому я попытался добавить еще одного провайдера следующим образом:

          {
        provide: MatSnackBarRef,
        useClass: MatSnackBarRef,
    },

И теперь я получаю новое сообщение:

main.ts:12 Ошибка: не удается разрешить все параметры для MatSnackBarRef: (?, ?).

Я не понимаю, почему я должен возиться с провайдерами. Кто-нибудь знает, что я делаю неправильно?

1 ответ

Когда вы видите этот тип сообщения

main.ts:12 Ошибка: не удается разрешить все параметры для MatSnackBarRef: (?, ?).

Это довольно четкое сообщение об ошибке, которое говорит вам, что зависимость, которую вы пытаетесь внедрить ( ) имеет две другие зависимости, и механизм внедрения зависимостей не находит их. Каждый вопросительный знак обозначают одну зависимость в конструкторе службы.

Проблема связана с тем, что вы написали

      {
        provide: MatSnackBarRef,
        useClass: MatSnackBarRef,
},

Здесь вы пытаетесь внедрить настоящую службу MatSnackBarRef, которая имеет две зависимости (см . конструктор MatSnackBarRef)

При модульном тестировании вы должны стараться как можно больше имитировать зависимости, чтобы не попасть в ад зависимостей (добавление зависимостей зависимостей на вашем тестовом стенде)

Вот простой макет зависимости (просто используйте пустой объект), но вы можете заменить любое свойство, необходимое в вашем тесте, своей собственной реализацией.

      {
        provide: MatSnackBarRef,
        useValue: {},
},
Другие вопросы по тегам