#angular #rxjs #observable #behaviorsubject
#angular #rxjs #наблюдаемый #behaviorsubject
Вопрос:
Если массив в ответе пуст, я хочу отобразить сообщение, в противном случае элементы массива.
В случае, если ответ содержит непустой массив, условие *ngIf принимает значение true, и сообщение отображается до тех пор, пока данные не будут загружены.
Фрагмент Html-шаблона:
<div *ngIf="personalAndStarredBookmarks$ amp;amp; (personalAndStarredBookmarks$ | async)?.size === 0; else personalBookmarksList" class="missing-category-bookmarks-message alert alert-info">
<p>No bookmarks yet</p>
</div>
<ng-template #personalBookmarksList>
<app-async-bookmark-list [bookmarks]="personalAndStarredBookmarks$" [shownSize]="10" [userData]="userData"></app-async-bookmark-list>
</ng-template>
Фрагмент компонента:
import { List } from 'immutable';
export class PersonalBookmarksListComponent implements OnInit {
personalAndStarredBookmarks$: Observable<List<Bookmark>>;
ngOnInit(): void {
this.personalAndStarredBookmarks$ = this.personalBookmarksStore.getPersonalBookmarks();
}
...
}
Хранилище использует BehaviourSubject, где он содержит ответ от службы, которая фактически выполняет HTTP-вызов.
Сохранить фрагмент
@Injectable()
export class PersonalBookmarksStore {
private _personalBookmarks: BehaviorSubject<List<Bookmark>> = new BehaviorSubject(List([]));
constructor(private personalBookmarkService: PersonalBookmarkService,
private keycloakService: KeycloakService
) {
keycloakService.loadUserProfile().then(keycloakProfile => {
this.userId = keycloakProfile.id;
this.loadInitialData();
});
}
private loadInitialData() {
this.personalBookmarkService.getAllPersonalBookmarks(this.userId)
.subscribe(
data => {
let bookmarks: Bookmark[] = <Bookmark[]>data;
this._personalBookmarks.next(List(bookmarks));
},
err => console.error('Error retrieving bookmarks', err)
);
}
getPersonalBookmarks(): Observable<List<Bookmark>> {
return this._personalBookmarks.asObservable();
}
...
}
Если я вызываю напрямую службу (а не хранилище) в компоненте, он ведет себя так, как ожидалось…
Комментарии:
1. Я думаю, вы намеревались написать
.length
, а не.size
в своем шаблоне.
Ответ №1:
Виновником является инициализация BehaviorSubject с пустым списком, который выдается, и условие оценивается как true:
private _personalBookmarks: BehaviorSubject<List<Bookmark>> = new BehaviorSubject(List([]));
Исправить — инициализировать BehaviorSubject с null
помощью или undefined
private _personalBookmarks: BehaviorSubject<List<Bookmark>> = new BehaviorSubject(null);
Ответ №2:
Вы должны реструктурировать свой шаблон для эффективной обработки асинхронных вызовов, назначив локальную переменную как
<ng-content*ngIf="personalAndStarredBookmarks$ | async as personalAndStarredBookmarks">
<div *ngIf="personalAndStarredBookmarks.size === 0; else personalBookmarksList"
class="missing-category-bookmarks-message alert alert-info">
<p>No bookmarks yet</p>
</div>
<ng-template #personalBookmarksList>
<app-async-bookmark-list [bookmarks]="personalAndStarredBookmarks" [shownSize]="10"
[userData]="userData">
</app-async-bookmark-list>
</ng-template>
<ng-content>
Благодаря этому вы можете эффективно обрабатывать все условия и загружать основное содержимое только после разрешения асинхронного вызова.
Смотрите ДЕМОНСТРАЦИЮ ЗДЕСЬ
Комментарии:
1. Спасибо, я обновил вопрос для ясности, но это должно быть зафиксировано с помощью оператора безопасности (?) и должно оцениваться как false, верно?… см angular.io/guide/template-syntax#safe-navigation-operator
2. @Adrian вам не нужно изначально назначать свой
BehaviorSubject
null и следовать опубликованному мной подходу. Дайте мне знать, если вы думаете иначе.3. Hei @Saksham, да, виновником был пустой массив при инициализации BehaviorSubject. Я понял это раньше, извините, см. Мой ответ и решение…
4. @Adrian да, я видел ваше решение, но то, которое я реализовал выше, более эффективно обеспечивает доступность при меньшем количестве сравнений.
5. Я не понимаю, как это более эффективно по сравнению с
(personalAndStarredBookmarks$ | async)?.size === 0
, который ожидает завершения асинхронной операции и выполняет сравнение… Это правда, что вам не нужно использовать асинхронный канал по строке, но в этой ситуации код более подробный…. У вас есть ссылка?