Мое приложение использует MatSnackBar для отображения информации об ошибках для пользователя на основе результатов нескольких вызовов API, которые инициируются нажатием кнопки.
Поскольку вызовы API могут возвращаться из серверной части в В разное время нам нужен способ обновления данных Snackbars новой информацией при возврате вызовов API. Для этого рассматриваемый компонент пользовательского интерфейса имеет ссылку на SnackbarService, и когда API вызывает ошибку, подробности ответа передаются в SnackbarService.
Сам SnackbarService имеет запись обо всех ошибках, которые имеют была вытолкнута из пользовательского интерфейса _snackbarData
, эта информация проталкивается через объект BehaviourSubject, который предоставляется снэк-панели через его конфигурацию Когда компонент пользовательского интерфейса передает информацию об ошибках в SnackbarService, он затем проталкивается через BehaviourSubject, а на панели с закусками появляется актуальный список всех ошибок, которые необходимо отобразить.
Это все работает нормально, если я вставьте консольные журналы, чтобы я мог точно видеть, когда подробности ошибок выдвигаются на снэк-бар, а снэк-бар получает их все правильно.
Проблема в том, что по какой-то причине снэк-бар отказывается отображать больше одной ошибки время, несмотря на использование * ngFor для отображения данных. Если я закрою и снова открою снэк-бар, все ошибки будут отображаться, как и ожидалось. Однако я хочу оставить снэк-бар открытым и добавлять к нему данные, а не закрывать и открывать их каждый раз, когда появляется новая ошибка.
Странным побочным эффектом этого и доказательством того, что снэк-бар правильно получает данные об ошибках, является то, что при нажатии на снэк-бар для отмены, вторая ошибка появляется на короткое время до того, как снэк-бар исчезает.
Могу ли я заставить пользовательский интерфейс снэк-бара обновляться при получении новых данных?
UI Component
ngOnInit() {
this._genericErrorService.genericErrorSubject$.pipe(takeUntil(this.destroy$)).subscribe((errorDetails: ErrorDetails) => {
this.syncingClasses = false;
console.log("Pushed error");
this._errorSnackbarService.pushErrorToSnackbar(errorDetails);
});
}
SnackbarService
export class ErrorSnackbarService {
private _snackbarData: ErrorDetails[];
errorDetailsSubject: BehaviorSubject<ErrorDetails[]> = new BehaviorSubject<ErrorDetails[]>(this._snackbarData);
constructor(private _snackbar: MatSnackBar) {
this._snackbarData = [];
}
pushErrorToSnackbar(errorDetails: ErrorDetails) {
this.appendSnackbarData(errorDetails);
this.errorDetailsSubject.next(this._snackbarData);
if(!this.isSnackbarActive()) {
this._snackbar.dismiss();
this.displaySnackbar();
} else { //This else causes the errors to be displayed as expected, without it the snackbar doesn't update.
this._snackbar.dismiss();
this.displaySnackbar();
}
}
}
private displaySnackbar() {
this._snackbar.openFromComponent(ErrorSnackbarComponent, {
data: this.errorDetailsSubject,
duration: 0,
});
this._snackbar._openedSnackBarRef.afterDismissed().pipe(take(1)).subscribe(res => {
this.clearSnackbar();
})
}
private appendSnackbarData(errorDetails: ErrorDetails) {
this._snackbarData.push(errorDetails);
}
clearSnackbar() {
this._snackbarData = [];
}
dismissSnackbar() {
this._snackbar.dismiss();
}
}
Snackbar Component
export class ErrorSnackbarComponent extends AbstractBaseComponent implements OnInit {
private _errorList: ErrorDetails[];
constructor(baseService: BaseService,
private _matSnackBarRef: MatSnackBarRef<ErrorSnackbarComponent>,
@Inject(MAT_SNACK_BAR_DATA) public data: BehaviorSubject<ErrorDetails[]>) {
super(baseService);
}
ngOnInit() {
this.data.subscribe(res => {
console.log("errorList: ", res);
this._errorList = res;
})
}
dismiss() {
this._matSnackBarRef.dismiss();
}
}
Шаблон Snackbar
<div (click)="dismiss()" class="pointer">
<div class="row-container">
<div class="row" *ngFor="let error of _errorList">
<div class="col-1 error-icon-container">
<mat-icon *ngIf="!isWarning(error.errorKey)" class="error-icon">cancel</mat-icon>
<mat-icon *ngIf="isWarning(error.errorKey)" class="warning-icon">warning</mat-icon>
</div>
<div class="col-11 margin-auto">
<span class="snackbar-text">
{{ getTranslateKey("errors." + error.errorKey) | translate }}
</span>
</div>
</div>
</div>
</div>