Использование 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: {},
},