Angular2/RxJS - обновляющая переменная после получения данных из Http наблюдаемого

97
9

Я хотел бы включить значок загрузчика (например, spinner) isLoaderEnabled, когда данные начнут загружаться из API и отключить их при успешном получении. Что было бы правильным способом отключить его?


Вот мой следующий код.


Мой компонент:


this.isLoaderEnabled = true;
this.meetingService.getList();

Мой сервис:


getList() {
this._http.get('../fake-data/someFile.json')
.map(response => response.json())
.subscribe(
data => {
this.dataStore.meetingList = data;
this.meetingListObserver.next(this.dataStore.meetingList);
},
err => console.log('>>>', 'Could not load meetings list. Error: ', err),
() => console.log('>>>', 'Done with getting meetings list.')
);
}

Спасибо.

спросил(а) 2021-01-19T16:04:32+03:00 2 месяца, 3 недели назад
1
Решение
131

Я думаю, что ваша проблема сложнее, чем кажется на первый взгляд;-) На самом деле XHR не поддерживает потоковое вещание, поэтому, когда первый обратный вызов, зарегистрированный в методе subscribe, называется, вы уже получили все данные.


Тем не менее XHR поддерживает событие onprogress (см. этот plunkr: http://plnkr.co/edit/8MDO2GsCGiOJd2y2XbQk?p=preview). Это позволяет получить подсказки о ходе загрузки. Это не поддерживается в поле Angular2, но вы


@Injectable()
export class CustomBrowserXhr extends BrowserXhr {
constructor(private service:ProgressService) {}
build(): any {
let xhr = super.build();
xhr.onprogress = (event) => {
service.progressEventObservable.next(event);
};
return <any>(xhr);
}
}

и переопределить поставщика BrowserXhr с расширенным:


bootstrap(AppComponent, [
HTTP_PROVIDERS,
provide(BrowserXhr, { useClass: CustomBrowserXhr })
]);

Служба выполнения может быть реализована следующим образом:


export class ProgressService {
progressEventObservable:Subject<any> = new Subject();
}

Ваш сервис может подписаться на службу прогресса, которая будет уведомляться, когда загрузка действительно начнется (т.е. первый раз, когда метод next для progressEventObservable вызывается для запроса):


getList() {
var subscription = this.progressService.subscribe(event => {
if (!this.spinner) {
this.spinner = true;
}
});
this._http.get('../fake-data/someFile.json')
.map(response => response.json())
.do(val => this.spinner = true)
.subscribe(
data => {
this.dataStore.meetingList = data;
this.meetingListObserver.next(this.dataStore.meetingList);
},
err => (...),
() => {
this.spinner = false;
subscription.unsubscribe();
})
);
}

Edit


Если вы хотите использовать счетчик в компоненте, а не в сервисе. Вы можете использовать выделенный наблюдаемый/объект, как описано ниже:


spinner$: Subject<boolean> = new Subject();
spinner: boolean = false;

getList() {
var subscription = this.progressService.subscribe(event => {
if (!this.spinner) {
this.spinner = true;
this.spinner$.next(this.spinner); // <-------
}
});
this._http.get('../fake-data/someFile.json')
.map(response => response.json())
.do(val => this.spinner = true)
.subscribe(
data => {
this.dataStore.meetingList = data;
this.meetingListObserver.next(this.dataStore.meetingList);
},
err => (...),
() => {
this.spinner = false;
this.spinner$.next(this.spinner); // <-------
subscription.unsubscribe();
})
);
}


Компонент может подписаться на spinner$, чтобы получать уведомления об изменениях:


@Component({
(...)
})
export class SomeCOmponent {
constructor(private meetingService:MeetingService) {
this.meetingService.spinner$.subscribe((spinner) {
this.isLoaderEnabled = spinner;
});
}
}

ответил(а) 2021-01-19T16:04:32+03:00 2 месяца, 3 недели назад
75

getList() {
this._http.get('../fake-data/someFile.json')
.map(response => response.json())
.do(val => this.spinner = true)
.subscribe(
data => {
this.dataStore.meetingList = data;
this.meetingListObserver.next(this.dataStore.meetingList);
},
err => console.log('>>>', 'Could not load meetings list. Error: ', err),
() => this.spinner = false)
);
}

ответил(а) 2021-01-19T16:04:32+03:00 2 месяца, 3 недели назад
62

Вам нужно сделать несколько трюков, чтобы они работали правильно:


    //use Observable.from as lock trigger BEFORE request is sent
var request:Observable<Response> = Observable.from([1], null).do(()=>
{
lock.lock();
}).flatMap(()=>
{
//use finally to unlock in any case
return this.http.post(url, body, options).finally(()=>
{
lock.unlock();
});
});
//share sequence to avoid multiple calls when using several subscribers
return request.share();

ответил(а) 2021-01-19T16:04:32+03:00 2 месяца, 3 недели назад
44

Если ваш компонент subscribe() в meetingListObserver, просто отключите его в функции обратного вызова подписки.


Если нет, добавьте еще одну Наблюдаемую или Субъект к службе и подпишитесь на нее. Когда данные вернутся из службы, вызовите next() в Observable или Subject. Пример использования объекта в службе см. В https://angular.io/docs/ts/latest/cookbook/component-communication.html#!#bidirectional-service

ответил(а) 2021-01-19T16:04:32+03:00 2 месяца, 3 недели назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема