Angular Multiple HTTP Requests with RxJS
Nov 15, 2016
Updated Feb 25, 2018 - 5 min readangular rxjs
This article has been updated to the latest version of Angular 7. The content is still likely be applicable for Angular 2 or other previous versions.
This article has been updated to use the new RxJS Pipeable Operators which is the new default for RxJS 6.
A typical pattern we run into with single page apps is to gather up data from multiple API endpoints and then display the gathered data to the user. Fetching numerous asynchronous requests and managing them can be tricky but with the Angular’s Http service and a little help from the included RxJS library, it can be accomplished in just a few of lines of code. There are multiple ways to handle multiple requests; they can be sequential or in parallel. In this post, we will cover both.
Let’s start with a simple HTTP request using the Angular Http service.
import { Component } from '@angular/core';
import { HttpClient } from '@angular/common/http';
@Component({
selector: 'app-root',
templateUrl: 'app/app.component.html'
})
export class AppComponent {
constructor(private http: HttpClient) { }
ngOnInit() {
this.http.get('/api/people/1').subscribe(json => console.log(json));
}
}
In our app, we have just a single component that pulls in Angular’s Http service via Dependency Injection. Angular will give us an instance of the Http service when it sees the signature in our component’s constructor.
Now that we have the service we call the service to fetch some data from our test API. We do this in the ngOnInit
. This is a life cycle hook where its ideal to fetch data. You can read more about ngOnInit
in the docs. For now, let’s focus on the HTTP call. We can see we have http.get()
that makes a GET request to /api/people/1
. We then call subscribe
to subscribe to the data when it comes back. When the data comes back, we just log the response to the console. So this is the simplest snippet of code to make a single request. Let’s next look at making two requests.
Subscribe
In our next example, we will have the following use case: We need to retrieve a character from the Star Wars API. To start, we have the id of the desired character we want to request.
When we get the character back, we then need to fetch that character’s homeworld from the same API but a different REST endpoint. This example is sequential. Make one request then the next.
Angular Form Essentials
Learn the essentials to get started creating amazing forms with Angular, get the E-Book now!
import { Component } from '@angular/core';
import { HttpClient } from '@angular/common/http';
@Component({
selector: 'app-root',
templateUrl: 'app/app.component.html'
})
export class AppComponent {
loadedCharacter: {};
constructor(private http: HttpClient) { }
ngOnInit() {
this.http.get('/api/people/1').subscribe(character => {
this.http.get(character.homeworld).subscribe(homeworld => {
character.homeworld = homeworld;
this.loadedCharacter = character;
});
});
}
}
Looking at the ngOnInit
method, we see our HTTP requests. First, we request to get a user from /api/user/1
. Once loaded we the make a second request a fetch the homeworld of that particular character. Once we get the homeworld, we add it to the character object and set the loadedCharacter
property on our component to display it in our template. This works, but there are two things to notice here. First, we are starting to see this nested pyramid structure in nesting our Observables which isn’t very readable. Second, our two requests were sequential. So let’s say our use case is we just want to get the homeworld of our character and to get that data we must load the character and then the homeworld. We can use a particular operator to help condense our code above.
MergeMap
In this example, we will use the mergeMap
operator. Let’s take a look at the code example first.
import { Component } from '@angular/core';
import { Http } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import { mergeMap } from 'rxjs/operators';
@Component({
selector: 'app-root',
templateUrl: 'app/app.component.html'
})
export class AppComponent {
homeworld: Observable<{}>;
constructor(private http: HttpClient) { }
ngOnInit() {
this.homeworld = this.http.get('/api/people/1').pipe(
mergeMap(character => this.http.get(character.homeworld))
);
}
}
In this example, we use the mergeMap
also known as flatMap
to map/iterate over the Observable values. So in our example when we get the homeworld, we are getting back an Observable inside our character Observable stream. This creates a nested Observable in an Observable. The mergeMap
operator helps us by subscribing and pulling the value out of the inner Observable and passing it back to the parent stream. This condenses our code quite a bit and removes the need for a nested subscription. This may take a little time to work through, but with practice, it can be a handy tool in our RxJS tool belt. Next, let’s take a look at multiple parallel requests with RxJS.
ForkJoin
In this next example, we are going to use an operator called forkJoin
. If you are familiar with Promises, this is very similar to Promise.all()
. The forkJoin()
operator allows us to take a list of Observables and execute them in parallel. Once every Observable in the list emits a value, the forkJoin
will emit a single Observable value containing a list of all the resolved values from the Observables in the list. In our example, we want to load a character and a characters homeworld. We already know what the ids are for these resources so we can request them in parallel.
import { Component } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import { forkJoin } from "rxjs/observable/forkJoin";
@Component({
selector: 'app-root',
templateUrl: 'app/app.component.html'
})
export class AppComponent {
loadedCharacter: {};
constructor(private http: HttpClient) { }
ngOnInit() {
let character = this.http.get('https://swapi.co/api/people/1');
let characterHomeworld = this.http.get('http://swapi.co/api/planets/1');
forkJoin([character, characterHomeworld]).subscribe(results => {
// results[0] is our character
// results[1] is our character homeworld
results[0].homeworld = results[1];
this.loadedCharacter = results[0];
});
}
}
In our example, we capture the character and characterHomeworld Observable in variables. Observables are lazy, so they won’t execute until someone subscribes. When we pass them into forkJoin
the forkJoin
operator will subscribe and run each Observable, gathering up each value emitted and finally emitting a single array value containing all the completed HTTP requests. This is a typical pattern with JavaScript UI programming. With RxJS this is relatively easy compared to using traditional callbacks.
With the mergeMap
/flatMap
and forkJoin
operators we can do pretty sophisticated asynchronous code with only a few lines of code. Check out the live example below!
Angular Multiple HTTP Requests with RxJS的更多相关文章
- [RxJS + AngularJS] Sync Requests with RxJS and Angular
When you implement a search bar, the user can make several different queries in a row. With a Promis ...
- [Angular] Intercept HTTP requests in Angular
Being able to intercept HTTP requests is crucial in a real world application. Whether it is for erro ...
- [Angular] Bind async requests in your Angular template with the async pipe and the "as" keyword
Angular allows us to conveniently use the async pipe to automatically register to RxJS observables a ...
- [Vue-rx] Cache Remote Data Requests with RxJS and Vue.js
A Promise invokes a function which stores a value that will be passed to a callback. So when you wra ...
- [Angular 2] Managing State in RxJS with StartWith and Scan
The scan operator in RxJS is the main key to managing values and states in your stream. Scan behaves ...
- [RxJS] Avoid mulit post requests by using shareReplay()
With the shareReplay operator in place, we would no longer fall into the situation where we have acc ...
- [Angular2 Form] Use RxJS Streams with Angular 2 Forms
Angular 2 forms provide RxJS streams for you to work with the data and validity as it flows out of t ...
- RxJS之Subject主题 ( Angular环境 )
一 Subject主题 Subject是Observable的子类.- Subject是多播的,允许将值多播给多个观察者.普通的 Observable 是单播的. 在 Subject 的内部,subs ...
- RxJS之工具操作符 ( Angular环境 )
一 delay操作符 源Observable延迟指定时间,再开始发射值. import { Component, OnInit } from '@angular/core'; import { of ...
随机推荐
- 【ARM-Linux开发】【Qt开发】Qt Creator自定义编译运行步骤
原文:http://www.linuxidc.com/Linux/2015-04/115763.htm 一直用Qt Creator开发.无它,只是因为linux下C++ IDE选择不多.同时因为我抛弃 ...
- 【DSP开发】CCS数据格式 load
CCS支持的.dat文件详解(转载于hellodsp) CCS支持的.dat文件的格式为: 定数 数据格式 起始地址 页类型 数据块大小 1651 其后是文件内容,每行表示一个数据. 定数固定为&qu ...
- leveldb单元测试之宏定义源码剖析
前言 leveldb 是一个库,没有 main() 函数入口, 故非常难理清其中的代码逻辑.但好在库中有非常多的单元测试代码,帮助读者理解其中的各个模块的功能.然而,测试代码个人觉得一开始看时非常费解 ...
- C语言--单层循环结构
一.PTA实验作业 题目1:最佳情侣身高 1.实验代码 int N, i; float height; char sex; printf("输入用户个数:\n"); scanf(& ...
- thinkphp5.1中使用Bootstrap4分页样式修改
1.找到thinkphp下的Boorstrap的源码 \thinkphp\library\think\paginator\driver\Bootstrap.php 2丶直接修改源码 <?php ...
- Timezone offset does not match system offset: 0 != -32400. Please, check your config files
apscheduler使用uWSGI的mule模块部署的时候报错, 因为系统时区和代码运行时区不一样导致. 解决办法:在初始化的时候指定上海的时区 scheduler = BlockingSchedu ...
- 顶级Python库
绝不能错过的24个顶级Python库 Python有以下三个特点: · 易用性和灵活性 · 全行业高接受度:Python无疑是业界最流行的数据科学语言 · 用于数据科学的Python库的数量优势 事实 ...
- getContextPath、getServletPath、getRequestURI、getRealPath、getRequestURL、getPathInfo();的区别
<% out.println("getContextPath: "+request.getContextPath()+"<br/>"); ou ...
- Codeforces 1097F. Alex and a TV Show
传送门 由于只要考虑 $\mod 2$ 意义下的答案,所以我们只要维护一堆的 $01$ 容易想到用 $bitset$ 瞎搞...,发现当复杂度 $qv/32$ 是可以过的... 一开始容易想到对每个集 ...
- BFS以及hash表判重的应用~
主要还是讲下hash判重的问题吧 这道题目用的是除法求余散列方式 前几天看了下算法导论 由于我们用的是线性再寻址的方式来解决冲突问题 所以hash表的大小(余数的范围)要包含我们要求的范围 对mod的 ...