Наблюдаемое, возвращаемое из http.get
, является наблюдаемым одноразового использования.
Для создания будущих значений вам потребуется создать тему прокси.
В приведенном ниже примере я объявляю личное Subject<Basket>
. И getBasket
, и addToBasket
создают субъекта, если он не существует. Это означает, что у вас не будет ни темы, ни одного и того же экземпляра субъекта, возвращенного всеми функциями.
После получения ответов http отправьте ответ через тему. Все подписчики получат новое значение.
export class BasketService {
constructor(private httpClient: HttpClient) {}
private apiUrl = 'http://0.0.0.0:8000';
private basket$: Subject<Basket>;
getBasket(): Observable<Basket> {
// Basket has already been loaded. Return the subject
if (this.basket$) {
return this.basket$.asObservable();
}
// Create a replay subject to ensure late subscribers receive an initial value
this.basket$ = new ReplaySubject<Basket>(1);
// Subscribe to the http client and emit the response
const url = `${this.apiUrl}/api-auth/basket/`;
this.httpClient.get<Basket>(url)
.subscribe(basket => this.basket$.next(basket));
// Return the subject
return this.basket$.asObservable();
}
addToBasket(sku: Sku, count: number): Observable<Basket> {
const url = `${this.apiUrl}/api-auth/basket/`;
const body = {items: [{sku: sku.pk, quantity: count}]};
// Create subject if it doesn't exist.
// It may be unlikely that you can addToBasket if you haven't loaded the basket, this is here for safety
if (!this.basket$) {
this.basket$ = new ReplaySubject<Basket>(1);
}
// Update the basket, emit the response to all current and future subscribers
this.httpClient.post<Basket>(url, body)
.subscribe(basket => this.basket$.next(basket));
return this.basket$.asObservable();
}
}
Это предполагает, что вы хотите выполнить GET только при первом вызове getBasket
. Если вы хотите всегда возвращать последнее значение корзины, вы можете создать тему в точке объявления и всегда запускать http GET.
private basket$: Subject<Basket> = new ReplaySubject<Basket>(1);
getBasket(): Observable<Basket> {
const url = `${this.apiUrl}/api-auth/basket/`;
this.http.get(url).subscribe(basket => this.basket$.next());
return this.basket$.asObservable();
}
addToBasket(sku: Sku, count: number): Observable<Basket> {
const url = `${this.apiUrl}/api-auth/basket/`;
const body = {items: [{sku: sku.pk, quantity: count}]};
this.httpClient.post<Basket>(url, body)
.subscribe(basket => this.basket$.next(basket));
return this.basket$.asObservable();
}
Если вы постоянно вызываете addToBasket
из одного и того же компонента вы можете предпочесть не возвращать объект из addToBasket
, но использовать следующий шаблон в своем компоненте:
basket: Basket;
ngOnInit() {
this.basketService.getBasket().subscribe(basket => {
this.basket = basket;
});
}
addToBasket(product) {
this.basketService.addToBasket(product);
}
, где addToBasket
просто выполняет HTTP POST и не возвращает наблюдаемое. Подписка getBasket
здесь просто получит обновленное значение.