Fire Observable Http Request Again if Condition Not Met

Angular 11 tutorial

In this Athwart 11 tutorial, we'll learn to build an Angular 11 Ajax Grime case awarding going through all the required steps from creating/simulating a REST API, scaffolding a new project, setting upward the essential APIs, and finally building and deploying your concluding awarding to the cloud.

Likewise learn to build a chat app with TypeScript, Angular 11 and PubNub/Chatkit

## What We'll Learn in this Angular 11 Tutorial?

  • We'll learn by example how to transport Become requests with URL query strings and parameters and procedure HTTP responses from Rest API servers in your angular application using Httplient for fetching and consuming JSON information, how to do mistake handling for HTTP errors using the RxJS throwError() and catchError() operators, how to retry failed HTTP requests in poor network connections and cancel pending requests using the RxJS retry() and takeUntil() operators, and finally how to deploy the awarding to Firebase hosting using the latest Athwart 8.3+ features.
  • Nosotros'll too run across how to employ Athwart services and RxJS Observables, and learn how to set Angular Material in our projection and mode the UI with Textile Blueprint components.
  • We'll see how to utilise the new ng deploy feature in Angular eight.three+ to easily deploy your Athwart 11 application from the control-line to Firebase hosting.

Notation: Please note that we are using HttpClient which is an improved version of the HTTP Customer API, bachelor starting from Angular version 4.three.0-rc.0. The old HTTP client is not available in Athwart 11.

You can also check out how to use HttpClient with Angular xi to build a news application that fetches JSON information from a third-party REST API in this tutorial.

Throughout this step past step Angular eleven tutorial, we are going to see a applied Crud example of how to employ the HttpClient that's available from the @angular/common/http packet, to make HTTP GET requests using the get() method.

What We'll Cover in this Tutorial?

We'll cover:

  • How to create a false and complete working CRUD Residue API,
  • How to install Angular CLI v11,
  • How to create an Athwart 11 projection using Angular CLI,
  • How to ready up Angular Cloth and fashion your application with Material Blueprint,
  • How to create Angular components, routing and navigation between them,
  • How to create and inject Angular services,
  • How to transport HTTP GET requests to servers using HttpClient,
  • How to apply the HttpParams grade to add together URL query strings in your HttpRequest,
  • How to subscribe and unsubscribe from RxJS Observables returned by HttpClient,
  • How to handle HTTP errors using the throwError() and catchError() operators,
  • How to retry failed HTTP requests using the RxJS retry() operator,
  • How to unsubscribe from RxJS Observables returned from HttpClient methods using the takeUntil() operator when requests are concelled,
  • How to build your awarding for product and deploy information technology to Firebase hosting using the new ng deploy control available from Angular 8.3+

The Steps of this Tutorial

The steps of this Angular 11 tutorial are as follows:

  • Step 1 — Setting upwardly Angular CLI 11
  • Footstep 2 — Initializing a New Angular 11 Example Projection
  • Step three — Setting upwardly a (Fake) JSON Rest API
  • Step 4 — Setting up Athwart HttpClient eleven in our Instance Project
  • Step 5 — Creating Athwart 11 Components
  • Stride 6 — Adding Angular 11 Routing
  • Footstep 7 — Styling the UI with Angular Material 11
  • Step 8 — Consuming the JSON Residue API with Angular HttpClient 11
  • Step 9 — Adding HTTP Error Handling with RxJS catchError() & HttpClient
  • Step 10 — Retrying Failed HTTP Requests with RxJS retry() & HttpClient
  • Step 11 — Unsubscribing from HttpClient Observables with RxJS takeUntil()
  • Footstep 12 — Calculation URL Query Parameters to the HttpClient get() Method
  • Step 13 — Getting the Full HTTP Response with Angular HttpClient eleven
  • Stride 14 — Requesting a Typed HTTP Response with Athwart HttpClient eleven
  • Pace fifteen — Building and Deploying your Angular 11 Application to Firebase Hosting

Let's become started by introducing Angular HttpClient, its features and why using it.

What is Angular HttpClient?

Front applications, congenital using frameworks like Athwart communicate with backend servers through Residuum APIs (which are based on the HTTP protocol) using either the XMLHttpRequest interface or the fetch() API.

Angular HttpClient makes use of the XMLHttpRequest interface that supports both modern and legacy browsers.

The HttpClient is bachelor from the @angular/mutual/http bundle and has a simplified API interface and powerful features such equally easy testability, typed request and response objects, request and response interceptors, reactive APIs with RxJS Observables, and streamlined error handling.

Why Angular HttpClient?

The HttpClient builtin service provides many advantages to Angular developers:

  • HttpClient makes information technology piece of cake to send and process HTTP requests and responses,
  • HttpClient has many builtin features for implementing test units,
  • HttpClient makes employ of RxJS Observables for handling asynchronous operations instead of Promises which simplify common web evolution tasks such as
  • - The concelation of HTTP requests,
  • - Listenning for the progression of file download and file upload operations,
  • - Like shooting fish in a barrel error handling,
  • - Retrying failed HTTP requests, etc.

Now later introducing HttpClient, let'south go along to building our example application starting with the prerequisites needed to successfully complete our Angular eleven tutorial.

Prerequisites

Earlier getting started you need a few prerequisites:

  • Basic noesis of TypeScript. Peculiarly the familiarity with Object Oriented concepts such as TypeScript classes and decorators.
  • A local development machine with Node x+, together with NPM 6+ installed. Node is required by the Angular CLI like the most frontend tools nowadays. You lot can but go to the downloads page of the official website and download the binaries for your operating system. You can also refer to your specific organization instructions for how to install Node using a parcel manager. The recommended way though is using NVM — Node Version Manager — a POSIX-compliant bash script to manage multiple active Node.js versions.

Notation: If y'all don't want to install a local surroundings for Angular development but even so want to effort the lawmaking in this tutorial, y'all can use Stackblitz, an online IDE for frontend development that you tin use to create an Angular project compatible with Athwart CLI.

If you have the previous prerequisites, you are prepare for the next steps of our Angular 11 tutorial that volition teach you by example how to use Angular HttpClient to transport HTTP GET requests for fetching JSON information and the various RxJS operators such as catchError(), tap(), retry(), and takeUntil() for implementing avant-garde features such as error handling, retrying failed HTTP requests and cancelling pending requests.

In the first step(s) of our tutorial, we'll come across how to install Athwart CLI 11 and create an example project from scratch.

Step 1 — Setting upward Athwart CLI eleven

In this step, we'll install the latest Angular CLI 11 version (at the time of writing this tutorial).

Note: These instructions are also valid for Angular eight/ix.

Angular CLI

Angular CLI is the official tool for initializing and working with Angular projects. To install information technology, open up a new command-line interface and run the following command:

                          $              npm install -g @angular/cli                      

At the time of writing this tutorial, athwart/cli v11 will be installed on your system.

If you run the ng version control, you lot should get a similar output:

            Angular CLI: 10.0.0 Node: 12.14.0 Bone: linux x64  Angular:  ...  Ivy Workspace:   Packet                      Version ------------------------------------------------------ @athwart-devkit/architect    0.1100.0-next.0 @angular-devkit/cadre         11.0.0-adjacent.0 @angular-devkit/schematics   11.0.0-side by side.0 @angular/cli                 11.0.0-next.0 @schematics/angular          11.0.0-side by side.0 @schematics/update           0.1100.0-next.0 rxjs                         6.5.4                      

In the adjacent pace, we'll larn how to intialize a new example projection from the command-line.

Step 2 — Initializing a New Angular xi Instance Project

In this stride, nosotros'll keep to create our instance project. Head back to your command-line interface and run the following commands:

                          $                            cd              ~              $              ng new angular-httpclient-example                      

The CLI will ask you a couple of questions — If Would you like to add Angular routing? Type y for Yes and Which stylesheet format would you similar to utilize? Cull CSS.

This volition instruct the CLI to automatically fix up routing in our project so we'll only demand to add the routes for our components to implement navigation in our application.

If you run the ng version command inside your project'due south folder, you should get a like output:

            Athwart CLI: xi.0.2 Node: 12.fourteen.0 OS: linux x64  Angular: eleven.0.1 ... animations, common, compiler, compiler-cli, core, forms ... linguistic communication-service, platform-browser, platform-browser-dynamic ... router Ivy Workspace: Yes  Package                           Version ----------------------------------------------------------- @angular-devkit/builder         0.1100.2 @athwart-devkit/build-angular     0.1100.two @angular-devkit/build-optimizer   0.1100.2 @angular-devkit/build-webpack     0.1100.2 @angular-devkit/core              11.0.2 @angular-devkit/schematics        11.0.2 @angular/cli                      11.0.2 @ngtools/webpack                  11.0.2 @schematics/angular               11.0.2 @schematics/update                0.1100.2 rxjs                              half dozen.5.4 typescript                        3.7.five webpack                           4.41.ii                      

Next, navigate to you project's folder and run the local development server using the following commands:

                          $                            cd              athwart-httpclient-example              $              ng serve                      

A local development server volition start listening on the http://localhost:4200/ accost. Angular CLI Ng Serve

Open your web browser and navigate to the http://localhost:4200/ accost to see your app up and running. This is a screenshot at this signal:

Angular 11 Project

You lot should now leave the development server running and first a new command-line interface for running the CLI commands of the next steps.

In the next step, nosotros'll acquire how to create a fake JSON Residuum API that we'll exist consuming in our Angular example application.

Footstep three — Setting up a (Imitation) JSON Rest API

Before we keep to develop our Angular awarding, we'll need to prepare a JSON Residue API that we tin eat using HttpClient.

Nosotros can also consume or fetch JSON data from 3rd-political party REST API servers just in this case, we choose to create a imitation REST API. Check out this tutorial for a existent REST API instance. As far as Angular concerned, there is no difference between consuming fake or real Rest APIs.

As said, yous can either use an external API service, create a real Residual API server or create a fake API using json-server. In this example nosotros'll utilise the concluding approach.

Then head over to a new command-line interface and start by installing json-server from npm in your project:

                          $                            cd              ~/angular-httpclient-example              $              npm install --salvage json-server                      

Adjacent, create a server binder in the root folder of your Angular project:

                          $              mkdir server              $                            cd              server                      

In the server folder, create a database.json file and add the post-obit JSON object:

This JSON file volition human action as a database for your REST API server. You can simply add some data to be served past your REST API or use Faker.js for automatically generating massive amounts of realistic fake data.

Go back to your command-line, navigate dorsum from the server folder, and install Faker.js from npm using the following command:

                          $                            cd              ..              $              npm install faker --save                      

At the time of creating this example, faker v4.1.0 will be installed.

Now, create a generate.js file and add the following code:

                          var              faker              =              crave              (              'faker'              );              var              database              =              {              products              :              []};              for              (              var              i              =              one              ;              i              <=              300              ;              i              ++              )              {              database              .              products              .              push              ({              id              :              i              ,              name              :              faker              .              commerce              .              productName              (),              description              :              faker              .              lorem              .              sentences              (),              toll              :              faker              .              commerce              .              cost              (),              imageUrl              :              "https://source.unsplash.com/1600x900/?product"              ,              quantity              :              faker              .              random              .              number              ()              });              }              console              .              log              (              JSON              .              stringify              (              database              ));                      

We first imported faker, side by side nosotros divers an object with one empty array for products. Next, we entered a for loop to create 300 imitation entries using faker methods like faker.commerce.productName() for generating product names. Check all the available methods. Finally we converted the database object to a string and log it to standard output.

Next, add the generate and server scripts to the packet.json file:

                                                      "scripts"              :                                          {                                          "ng"              :                                          "ng"              ,                                          "start"              :                                          "ng serve"              ,                                          "build"              :                                          "ng build"              ,                                          "test"              :                                          "ng examination"              ,                                          "lint"              :                                          "ng lint"              ,                                          "e2e"              :                                          "ng e2e"              ,                                          "generate"              :                                          "node ./server/generate.js > ./server/database.json"              ,                                          "server"              :                                          "json-server --watch ./server/database.json"                                          }              ,                                                  

Side by side, head back to your command-line interface and run the generate script using the following command:

Finally, run the REST API server by executing the post-obit command:

Y'all can now send HTTP requests to the server simply like whatever typical REST API server. Your server will be available from the http://localhost:3000/ address.

REST API Server

These are the API endpoints we'll be able to use via our JSON Residuum API server:

  • Go /products for getting the products,
  • Go /products/<id> for getting a unmarried product by id,
  • Mail /products for creating a new production,
  • PUT /products/<id> for updating a production by id,
  • PATCH /products/<id> for partially updating a product by id,
  • DELETE /products/<id> for deleting a product by id.

You lot can use _page and _limit parameters to get paginated data. In the Link header yous'll get first, prev, next and last links.

For example:

GET /products?_page=1 for getting the offset page of information, GET /products?_page=1&_limit=5 for getting the first five products of the offset page of data.

Note: You tin use other features such as filters, sorting and ordering. For more than information, bank check out the docs.

Leave the JSON Residue API server running and open a new command-line interface for typing the commands of the next steps.

Equally a summary of what we take done — Nosotros installed Angular CLI and initialized a new project based on the latest Angular 11 version. And so, nosotros created a REST API using json-server based on a JSON file. In the next step of our Angular 11 tutorial, we'll learn how to fix HttpClient in our Athwart 11 project.

Step 4 — Setting up Angular 11 HttpClient in our Case Project

In this footstep, we'll go along to prepare the HttpClient module in our example.

HttpClient lives in a carve up Athwart module, so nosotros'll need to import it in our primary awarding module before we tin can use it.

Open your case projection with a code editor or IDE. I'll be using Visual Studio Code.

Next, open the src/app/app.module.ts file, import HttpClientModule and add it to the imports array of the module as follows:

                          import              {              BrowserModule              }              from              '@angular/platform-browser'              ;              import              {              NgModule              }              from              '@angular/core'              ;              import              {              AppRoutingModule              }              from              './app-routing.module'              ;              import              {              AppComponent              }              from              './app.component'              ;              import              {              HttpClientModule              }              from              '@angular/common/http'              ;              @              NgModule              ({              declarations              :              [              AppComponent              ,              ],              imports              :              [              BrowserModule              ,              AppRoutingModule              ,              HttpClientModule              ],              providers              :              [],              bootstrap              :              [              AppComponent              ]              })              export              course              AppModule              {              }                      

That's all, nosotros are now ready to use the HttpClient service in our project just before that we demand to create a couple of components — The habitation and about components. This is what we'll learn to exercise in the side by side step.

Step 5 — Creating Angular 11 Components

In this footstep, nosotros'll proceed to create the Angular components that control our application UI.

Head back to a new command-line interface and run the following command:

                          $                            cd              ~/angular-httpclient-example              $              ng generate component home                      

This is the output of the command:

            CREATE src/app/dwelling house/dwelling.component.html (xix bytes) CREATE src/app/home/habitation.component.spec.ts (614 bytes) CREATE src/app/home/habitation.component.ts (261 bytes) CREATE src/app/home/home.component.css (0 bytes) UPDATE src/app/app.module.ts (467 bytes)                      

The CLI created iv files for the component and added it to the declarations assortment in the src/app/app.module.ts file.

Side by side, allow's create the about component using the following command:

                          $              ng generate component nigh                      

Next, open the src/app/almost/nigh.component.html and add the following lawmaking:

                          <p              style=              "padding: 13px;"              >              An Angular 11 example application that demonstrates how to use HttpClient to swallow REST APIs              </p>                      

We'll update the dwelling house component in the following steps.

In the next stride of our Angular xi tutorial, we'll add these components to the router.

Step 6 — Adding Angular 11 Routing

In this step, we'll go along to add routing to our example.

Head back to the src/app/app-routing.module.ts file, that was automatically created by Athwart CLI for routing configuration, and import the components and then add together the routes every bit follows:

                          import              {              NgModule              }              from              '@angular/core'              ;              import              {              Routes              ,              RouterModule              }              from              '@angular/router'              ;              import              {              HomeComponent              }              from              './dwelling house/home.component'              ;              import              {              AboutComponent              }              from              './nigh/near.component'              ;              const              routes              :              Routes              =              [              {              path              :              ''              ,              redirectTo              :              'home'              ,              pathMatch              :              'total'              },              {              path              :              'habitation'              ,              component              :              HomeComponent              },              {              path              :              'about'              ,              component              :              AboutComponent              },              ];              @              NgModule              ({              imports              :              [              RouterModule              .              forRoot              (              routes              )],              exports              :              [              RouterModule              ]              })              consign              class              AppRoutingModule              {              }                      

We offset imported the home and about components, next nosotros added iii routes including a route for redirecting the empty path to the abode component, so when the user visits the app, they volition exist redirected to the habitation page.

In the next step of our example, we'll set up Angular Material in our project for styling our UI.

Pace 7 — Styling the UI with Angular Textile eleven

In this footstep of our Angular 11 tutorial, we'll keep to add together Angular Material to our project and style our application UI.

Athwart Material provides Cloth Blueprint components that allow developers to create professional UIs. Setting upwardly Athwart Textile in our project is much easier now with the new ng add together command of the Angular CLI v7+.

Head dorsum to your command-line interface, and run the post-obit command from the root of your project:

                          $              ng add @athwart/material                      

You'll be asked for choosing a theme, choose Indigo/Pink.

For the other options — Ready HammerJS for gesture recognition? and Gear up browser animations for Angular Material? Simply press Enter in your keyboard to choose the default answers.

Next, open the src/styles.css file and add a theme:

                          @import              "~@athwart/textile/prebuilt-themes/indigo-pink.css"              ;                      

Each Angular Fabric component has a separate module that you demand to import before you can utilise the component. Open up the src/app/app.module.ts file and add the post-obit imports:

                          import              {              MatToolbarModule              ,              MatIconModule              ,              MatCardModule              ,              MatButtonModule              ,              MatProgressSpinnerModule              }              from              '@angular/material'              ;                      

We imported the following modules:

  • MatToolbar that provides a container for headers, titles, or actions.
  • MatCard that provides a content container for text, photos, and actions in the context of a unmarried discipline.
  • MatButton that provides a native <button> or <a> element enhanced with Textile Blueprint styling and ink ripples.
  • MatProgressSpinner that provides a circular indicator of progress and activity.

Next, you need to include these modules in the imports array:

                          @              NgModule              ({              declarations              :              [              AppComponent              ,              HomeComponent              ,              AboutComponent              ],              imports              :              [              BrowserModule              ,              AppRoutingModule              ,              HttpClientModule              ,              BrowserAnimationsModule              ,              MatToolbarModule              ,              MatIconModule              ,              MatButtonModule              ,              MatCardModule              ,              MatProgressSpinnerModule              ],              providers              :              [],              bootstrap              :              [              AppComponent              ]              })              consign              class              AppModule              {              }                      

Next, open the src/app/app.component.html file and update it equally follows:

                          <mat-toolbar              colour=              "primary"              >              <h1>              ngStore              </h1>              <button              mat-push              routerLink=              "/"              >Home</push button>              <button              mat-button              routerLink=              "/about"              >Virtually</push>              </mat-toolbar>              <router-outlet></router-outlet>                      

Nosotros created the beat of our awarding containing a top bar with two navigation buttons to the dwelling and near components.

As a summary of what nosotros did until this point of our tutorial — We have setup HttpClient and Athwart Fabric v11 in our project, created the home and near components and configured routing, and finaly added the crush of our awarding containing a topbar with navigation.

In the next step of our tutorial, nosotros'll learn how to fetch the JSON data from our REST API server using HttpClient v11.

Also read 3+ ways to integrate Bootstrap with Athwart and how to style Angular xi UIs with Bootstrap 4.

Stride eight — Consuming the JSON REST API with Angular HttpClient 11

In this pace, we'll proceed to consume JSON data from our Residuum API server in our example awarding.

We'll need to create an Athwart service for encapsulating the code that deals with consuming information from the Rest API server.

A service is a singleton that can be injected by other services and components using the Angular dependency injection.

In software engineering, dependency injection is a technique whereby 1 object supplies the dependencies of some other object. Source

Now, let's generate an Athwart service that interfaces with the JSON REST API. Head back to your command-line interface and run the following control:

                          $              ng generate service data                      

Next, open the src/app/data.service.ts file, import and inject HttpClient as follows:

                          import              {              Injectable              }              from              '@angular/cadre'              ;              import              {              HttpClient              }              from              '@angular/common/http'              ;              @              Injectable              ({              providedIn              :              'root'              })              export              class              DataService              {              private              REST_API_SERVER              =              "http://localhost:3000"              ;              constructor              (              private              httpClient              :              HttpClient              )              {              }              }                      

We imported and injected the HttpClient service every bit a individual httpClient instance. Nosotros also divers the REST_API_SERVER variable that holds the address of our Residuum API server.

Adjacent, add together a sendGetRequest() method that sends a GET asking to the Residual API endpoint to retrieve JSON data:

                          import              {              Injectable              }              from              '@angular/core'              ;              import              {              HttpClient              }              from              '@angular/mutual/http'              ;              @              Injectable              ({              providedIn              :              'root'              })              consign              class              DataService              {              private              REST_API_SERVER              =              "http://localhost:3000"              ;              constructor              (              private              httpClient              :              HttpClient              )              {              }              public              sendGetRequest              (){              return              this              .              httpClient              .              become              (              this              .              REST_API_SERVER              );              }              }                      

The method merely invokes the go() method of HttpClient to transport Get requests to the Residuum API server.

Adjacent, nosotros at present demand to use this service in our home component. Open the src/app/dwelling/habitation.component.ts file, import and inject the data service as follows:

                          import              {              Component              ,              OnInit              }              from              '@angular/cadre'              ;              import              {              DataService              }              from              '../data.service'              ;              @              Component              ({              selector              :              'app-home'              ,              templateUrl              :              './home.component.html'              ,              styleUrls              :              [              './home.component.css'              ]              })              export              class              HomeComponent              implements              OnInit              {              products              =              [];              constructor              (              private              dataService              :              DataService              )              {              }              ngOnInit              ()              {              this              .              dataService              .              sendGetRequest              ().              subscribe              ((              information              :              any              [])              =>              {              console              .              log              (              data              );              this              .              products              =              data              ;              })              }              }                      

Nosotros imported and injected DataService equally a private dataService instance via the component constructor.

Side by side, nosotros defined a products variable and called the sendGetRequest() method of the service for fetching information from the JSON REST API server.

Since the sendGetRequest() method returns the return value of the HttpClient.get() method which is an RxJS Observable, we subscribed to the returned Observable to actually ship the HTTP Become request and process the HTTP response.

When data is received, we added it in the products array.

Next, open the src/app/home/home.component.html file and update it as follows:

                          <div              style=              "padding: 13px;"              >              <mat-spinner              *              ngIf=              "products.length === 0"              ></mat-spinner>              <mat-card              *              ngFor=              "let product of products"              style=              "margin-top:11px;"              >              <mat-card-header>              <mat-card-title>{{product.name}}</mat-card-title>              <mat-carte du jour-subtitle>{{production.price}} $/ {{product.quantity}}              </mat-card-subtitle>              </mat-carte-header>              <mat-card-content>              <p>              {{product.description}}              </p>              <img              fashion=              "height:100%; width: 100%;"              src=              "{{ product.imageUrl }}"              />              </mat-card-content>              <mat-card-actions>              <button              mat-button              >              Buy product</button>              </mat-card-actions>              </mat-carte>              </div>                      

We used the <mat-spinner> component for showing a loading spinner when the length of the products array equals zero i.due east before no data is received from the Residuum API server.

Next, we iterated over the products array using ngFor and used a Cloth card to display the proper noun, toll, quantity, description and image of each product.

This is a screenshot of the home page subsequently JSON data is fetched:

Angular 11 Example

Next, we'll meet how to add error treatment to our service.

Footstep 9 — Adding HTTP Error Handling with RxJS catchError() & HttpClient

In this stride, nosotros'll go on to add error handling in our example application.

The Angular's HttpClient methods tin can exist easily used with the catchError() operator from RxJS, since they render Observables, via the piping() method for catching and treatment errors. We simply demand to ascertain a method to handle errors within your service.

At that place are 2 types of errors in front-end applications:

  • Client-side errors such as network issues and JavaScript syntax and type errors. These errors return ErrorEvent objects.
  • Server-side errors such as code errors in the server and database access errors. These errors render HTTP Error Responses.

As such, we simply need to bank check if an mistake is an instance of ErrorEvent to become the type of the fault so nosotros can handle it accordingly.

At present, let's come across this by instance. Open up the src/app/data.service.ts file and update it accordingly:

                          import              {              Injectable              }              from              '@athwart/core'              ;              import              {              HttpClient              ,              HttpErrorResponse              }              from              "@angular/common/http"              ;              import              {              throwError              }              from              'rxjs'              ;              import              {              retry              ,              catchError              }              from              'rxjs/operators'              ;              @              Injectable              ({              providedIn              :              'root'              })              export              course              DataService              {              private              REST_API_SERVER              =              "http://localhost:3000/products"              ;              constructor              (              private              httpClient              :              HttpClient              )              {              }              handleError              (              error              :              HttpErrorResponse              )              {              permit              errorMessage              =              'Unknown error!'              ;              if              (              mistake              .              error              instanceof              ErrorEvent              )              {              // Client-side errors              errorMessage              =              `              Error              :              $              {              error              .              fault              .              bulletin              }              `              ;              }              else              {              // Server-side errors              errorMessage              =              `              Error              Code              :              $              {              error              .              status              }              \              nMessage              :              $              {              error              .              message              }              `              ;              }              window              .              alert              (              errorMessage              );              render              throwError              (              errorMessage              );              }              public              sendGetRequest              (){              return              this              .              httpClient              .              become              (              this              .              REST_API_SERVER              ).              pipe              (              catchError              (              this              .              handleError              ));              }              }                      

As yous tin can see, this needs to exist done for each service in your awarding which is fine for our example since it only contains one service but once your awarding starts growing with many services which may all throw errors you need to use amend solutions instead of using the handleError method per each service which is error-decumbent. 1 solution is to handle errors globally in your Angular application using HttpClient interceptors.

This is a screenshot of an error on the console if the server is unreachable:

Angular HttpClient Error Example

In the adjacent stride, we'll see how to better our data service by automatically retry sending the failed HTTP requests.

Pace 10 — Retrying Failed HTTP Requests with RxJS retry() & HttpClient

In this footstep of our Angular 11 tutorial, we'll see how to apply the retry() operator of RxJS with HttpClient to automatically resubscribing to the returned Observable which results in resending the failed HTTP requests.

In many cases, errors are temporary and due to poor network conditions then just trying again will brand them go away automatically. For example, in mobile devices network interruptions are frequent so if the user tries again, they may go a successful response. Instead of letting users manually retry, let's see how to do that automatically in our example application.

The RxJS library provides several retry operators. Amongst them is the retry() operator which allows you to automatically re-subscribe to an RxJS Observable a specified number of times. Re-subscribing to the Appreciable returned from an HttpClient method has the event of resending the HTTP request to the server so users don't need to repeat the performance or reload the application.

You tin can apply the RxJS retry() operator by piping it (using the pipe() method) onto the Observable returned from the HttpClient method earlier the error handler.

Get to the src/app/data.service.ts file and import the retry() operator:

                          import              {              retry              ,              catchError              }              from              'rxjs/operators'              ;                      

Next update the sendGetRequest() method every bit follows:

                          public              sendGetRequest              (){              return              this              .              httpClient              .              go              (              this              .              REST_API_SERVER              ).              pipe              (              retry              (              3              ),              catchError              (              this              .              handleError              ));              }                      

This volition retry sending the failed HTTP request three times.

In the side by side step, we'll see how to unsubscribe from RxJS Observables in our instance home component.

Stride 11 — Unsubscribing from HttpClient Observables with RxJS takeUntil()

In this step of our Angular 11 tutorial, we'll learn nearly why we need and how to unsubscribe from Observables in our code using the takeUntil() operator.

Showtime of all, do you demand to unsubscribe from the Observables returned by the HttpClient methods?

Generally, you need to manually unsubscribe from any subscribed RxJS Observables in your Angular components to avoid retention leaks but in the case of HttpClient, this is automatically handled by Angular by unsubscribing when the HTTP response is received. Nonetheless, there are some cases when you need to manually unsubscribe for example to cancel pending requests when users are well-nigh to exit the component.

Nosotros can merely call the unsubscribe() method from the Subscription object returned by the subscribe() method in the ngOnDestroy() life-cycle method of the component to unsubscribe from the Observable.

There is also a better way to unsubscribe from or consummate Observables past using the takeUntil() operator.

The takeUntil() operator emits the values emitted by the source Appreciable until a notifier Observable emits a value.

Permit'southward see how to use this operator to complete Observables when the component is destroyed.

Bank check out How to cancel/unsubscribe all pending HTTP requests angular 4+.

Open up the src/app/abode/home.component.ts file and update information technology as follows:

                          import              {              Component              ,              OnInit              ,              OnDestroy              }              from              '@athwart/core'              ;              import              {              DataService              }              from              '../data.service'              ;              import              {              takeUntil              }              from              'rxjs/operators'              ;              import              {              Subject              }              from              'rxjs'              ;              @              Component              ({              selector              :              'app-home'              ,              templateUrl              :              './domicile.component.html'              ,              styleUrls              :              [              './habitation.component.css'              ]              })              export              class              HomeComponent              implements              OnInit              ,              OnDestroy              {              products              =              [];              destroy$              :              Subject              <              boolean              >              =              new              Subject              <              boolean              >              ();              constructor              (              individual              dataService              :              DataService              )              {              }              ngOnInit              ()              {              this              .              dataService              .              sendGetRequest              ().              pipe              (              takeUntil              (              this              .              destroy$              )).              subscribe              ((              information              :              any              [])              =>              {              console              .              log              (              data              );              this              .              products              =              information              ;              })              }              ngOnDestroy              ()              {              this              .              destroy$              .              side by side              (              true              );              // Unsubscribe from the subject              this              .              destroy$              .              unsubscribe              ();              }              }                      

Nosotros first imported the OnDestroy interface, Subject and the takeUntil() operator. Next, we implemented the OnDestroy interface and added the ngOnDestroy() lifecycle hook to the component.

Next, nosotros created an instance of Subject which can emit boolean values (the type of the value doesn't actually affair in this instance) that will be used every bit the notifier of the takeUntil() operator.

Next, in the ngOnInit() lifecycle hook, we called the sendGetRequest() of our data service and called the pipage() method of the returned Observable to piping the takeUnitl() operator and finaly subscribed to the combined Observable. In the body of the subscribe() method, nosotros added the logic to put the fetched information of the HTTP response in the products array.

The takeUntil() operator allows a notified Observable to emit values until a value is emitted from a notifier Appreciable.

When Angular destroys a component it calls the ngOnDestroy() lifecycle method which, in our case, calls the next() method to emit a value so RxJS completes all subscribed Observables.

That's information technology. In this pace, we have added the logic to cancel any pending HTTP request by unsubscribing from the returned Observable in case the user descides to navigate abroad from the component before the HTTP response is received.

Also read how to Unsubscribe from the RxJS subjects when the Angular component is destroyed

In the next step of our Angular eleven tutorial, we'll meet how to utilise URL query parameters with the get() method of HttpClient.

Step 12 — Adding URL Query Parameters to the HttpClient get() Method

In this footstep, we'll start adding the logic for implementing pagination in our example awarding. We'll come across how to use URL query parameters via fromString and HttpParams to provide the appropriate values for the the _page and _limit parameters of the /products endpoint of our JSON Rest API server for getting paginated data.

Open the src/app/information.service.ts file and offset past adding the post-obit the import for HttpParams:

                          import              {              HttpClient              ,              HttpErrorResponse              ,              HttpParams              }              from              "@angular/common/http"              ;                      

Next, update the sendGetRequest() method equally follows:

                          public              sendGetRequest              (){              // Add together safe, URL encoded_page parameter                            const              options              =              {              params              :              new              HttpParams              ({              fromString              :              "_page=ane&_limit=20"              })              };              return              this              .              httpClient              .              go              (              this              .              REST_API_SERVER              ,              options              ).              pipe              (              retry              (              3              ),              catchError              (              this              .              handleError              ));              }                      

We used HttpParams and fromString to create HTTP query parameters from the _page=ane&_limit=xx string. This tells to returns the first page of 20 products.

Now the sendGetRequest() will exist used to retrieve the first page of data. The received HTTP response will comprise a Link header with data almost the start, previous, next and last links of data pages.

In the Link header y'all'll get first, prev, next and last links. In the next stride, we'll run into how to extract these pagination links past parsing total HTTP responses.

Stride 13 — Getting the Total HTTP Response with Angular HttpClient 11

In this ste, we'll proceed by implementing the logic for retrieving pagination data from the Link header contained in the HTTP response received from the JSON REST API server.

By default, HttpClient does but provide the response torso simply in our case we need to parse the Link header for pagination links then we need to tell HttpClient that we want the total HttpResponse using the find choice.

The Link header in HTTP allows the server to signal an interested client to some other resources containing metadata about the requested resource.Wikipedia

Get to the src/app/information.service.ts file and import the RxJS tap() operator:

                          import              {              retry              ,              catchError              ,              tap              }              from              'rxjs/operators'              ;                      

Next, ascertain the following string variables:

                          public              kickoff              :              string              =              ""              ;              public              prev              :              cord              =              ""              ;              public              next              :              string              =              ""              ;              public              last              :              cord              =              ""              ;                      

Next, define the parseLinkHeader() method which parses the Link header and populate the previous variables accordingly:

                          parseLinkHeader              (              header              )              {              if              (              header              .              length              ==              0              )              {              render              ;              }              let              parts              =              header              .              split              (              ','              );              var              links              =              {};              parts              .              forEach              (              p              =>              {              let              section              =              p              .              split              (              ';'              );              var              url              =              section              [              0              ].              replace              (              /<              (              .*              )              >/              ,              '$1'              ).              trim              ();              var              name              =              section              [              1              ].              supersede              (              /rel="              (              .*              )              "/              ,              '$1'              ).              trim              ();              links              [              name              ]              =              url              ;              });              this              .              commencement              =              links              [              "offset"              ];              this              .              last              =              links              [              "last"              ];              this              .              prev              =              links              [              "prev"              ];              this              .              next              =              links              [              "adjacent"              ];              }                      

Side by side, update the sendGetRequest() as follows:

                          public              sendGetRequest              (){              // Add rubber, URL encoded _page and _limit parameters                            return              this              .              httpClient              .              get              (              this              .              REST_API_SERVER              ,              {              params              :              new              HttpParams              ({              fromString              :              "_page=1&_limit=20"              }),              observe              :              "response"              }).              pipage              (              retry              (              iii              ),              catchError              (              this              .              handleError              ),              tap              (              res              =>              {              panel              .              log              (              res              .              headers              .              become              (              'Link'              ));              this              .              parseLinkHeader              (              res              .              headers              .              get              (              'Link'              ));              }));              }                      

We added the discover option with the response value in the options parameter of the get() method so we can take the full HTTP response with headers. Next, we use the RxJS tap() operator for parsing the Link header earlier returning the final Appreciable.

Since the sendGetRequest() is at present returning an Observable with a full HTTP response, we need to update the habitation component and so open the src/app/dwelling house/home.component.ts file and import HttpResponse as follows:

                          import              {              HttpResponse              }              from              '@angular/common/http'              ;                      

Adjacent, update the subscribe() method as follows:

                          ngOnInit              ()              {              this              .              dataService              .              sendGetRequest              ().              pipe              (              takeUntil              (              this              .              destroy$              )).              subscribe              ((              res              :              HttpResponse              <              any              >              )              =>              {              console              .              log              (              res              );              this              .              products              =              res              .              torso              ;              })              }                      

We tin can now admission the data from the body object of the received HTTP response.

Next, go dorsum to the src/app/data.service.ts file and add the following method:

                          public              sendGetRequestToUrl              (              url              :              cord              ){              return              this              .              httpClient              .              get              (              url              ,              {              detect              :              "response"              }).              pipe              (              retry              (              3              ),              catchError              (              this              .              handleError              ),              tap              (              res              =>              {              panel              .              log              (              res              .              headers              .              become              (              'Link'              ));              this              .              parseLinkHeader              (              res              .              headers              .              go              (              'Link'              ));              }));              }                      

This method is similar to sendGetRequest() except that it takes the URL to which we demand to send an HTTP Go request.

Go back to the src/app/home/home.component.ts file and add ascertain the following methods:

                          public              firstPage              ()              {              this              .              products              =              [];              this              .              dataService              .              sendGetRequestToUrl              (              this              .              dataService              .              first              ).              pipe              (              takeUntil              (              this              .              destroy$              )).              subscribe              ((              res              :              HttpResponse              <              any              >              )              =>              {              console              .              log              (              res              );              this              .              products              =              res              .              torso              ;              })              }              public              previousPage              ()              {              if              (              this              .              dataService              .              prev              !==              undefined              &&              this              .              dataService              .              prev              !==              ''              )              {              this              .              products              =              [];              this              .              dataService              .              sendGetRequestToUrl              (              this              .              dataService              .              prev              ).              pipe              (              takeUntil              (              this              .              destroy$              )).              subscribe              ((              res              :              HttpResponse              <              any              >              )              =>              {              console              .              log              (              res              );              this              .              products              =              res              .              body              ;              })              }              }              public              nextPage              ()              {              if              (              this              .              dataService              .              next              !==              undefined              &&              this              .              dataService              .              next              !==              ''              )              {              this              .              products              =              [];              this              .              dataService              .              sendGetRequestToUrl              (              this              .              dataService              .              adjacent              ).              pipe              (              takeUntil              (              this              .              destroy$              )).              subscribe              ((              res              :              HttpResponse              <              any              >              )              =>              {              console              .              log              (              res              );              this              .              products              =              res              .              torso              ;              })              }              }              public              lastPage              ()              {              this              .              products              =              [];              this              .              dataService              .              sendGetRequestToUrl              (              this              .              dataService              .              concluding              ).              pipe              (              takeUntil              (              this              .              destroy$              )).              subscribe              ((              res              :              HttpResponse              <              any              >              )              =>              {              console              .              log              (              res              );              this              .              products              =              res              .              torso              ;              })              }                      

Finally, add open the src/app/home/domicile.component.html file and update the template equally follows:

                          <div              style=              "padding: 13px;"              >              <mat-spinner              *              ngIf=              "products.length === 0"              ></mat-spinner>              <mat-card              *              ngFor=              "let product of products"              manner=              "margin-tiptop:11px;"              >              <mat-card-header>              <mat-carte-title>#{{product.id}} {{product.proper noun}}</mat-menu-title>              <mat-card-subtitle>{{product.price}} $/ {{product.quantity}}              </mat-card-subtitle>              </mat-card-header>              <mat-bill of fare-content>              <p>              {{product.description}}              </p>              <img              way=              "meridian:100%; width: 100%;"              src=              "{{ product.imageUrl }}"              />              </mat-card-content>              <mat-carte-actions>              <button              mat-button              >              Purchase product</push>              </mat-card-actions>              </mat-carte du jour>              </div>              <div>              <push button              (              click              )              ="              firstPage              ()"              mat-button              >              Showtime</push>              <push button              (              click              )              ="              previousPage              ()"              mat-button              >              Previous</button>              <button              (              click              )              ="              nextPage              ()"              mat-button              >              Next</button>              <button              (              click              )              ="              lastPage              ()"              mat-button              >              Last</push>              </div>                      

This is a screenshot of our application:

Step 14 — Requesting a Typed HTTP Response with Angular HttpClient xi

In this step, we'll see how to use typed HTTP responses in our example application.

Angular HttpClient allows y'all to specify the type of the response object in the request object, which brand consuming the response easier and straightforward. This as well enables type assertion during the compile fourth dimension.

Let's start by defining a custom type using a TypeScript interface with the required properties.

Caput dorsum to your command-line interface and run the following command from the root of your projection:

                          $              ng generate interface  product                      

Next, open the src/app/product.ts file and update it equally follows:

                          export              interface              Production              {              id              :              number              ;              name              :              string              ;              description              :              string              ;              price              :              number              ;              quantity              :              number              ;              imageUrl              :              string              ;              }                      

Next, specify the Production interface every bit the HttpClient.get() call's type parameter in the information service. Get back to the src/app/data.service.ts file and import the Product interface:

                          import              {              Product              }              from              './production'              ;                      

Side by side:

                          public              sendGetRequest              (){              render              this              .              httpClient              .              get              <              Product              []              >              (              this              .              REST_API_SERVER              ,              {              params              :              new              HttpParams              ({              fromString              :              "_page=1&_limit=20"              }),              discover              :              "response"              }).              pipe              (              retry              (              3              ),              catchError              (              this              .              handleError              ),              tap              (              res              =>              {              console              .              log              (              res              .              headers              .              go              (              'Link'              ));              this              .              parseLinkHeader              (              res              .              headers              .              get              (              'Link'              ));              }));              }              public              sendGetRequestToUrl              (              url              :              string              ){              return              this              .              httpClient              .              get              <              Production              []              >              (              url              ,              {              discover              :              "response"              }).              piping              (              retry              (              3              ),              catchError              (              this              .              handleError              ),              tap              (              res              =>              {              console              .              log              (              res              .              headers              .              become              (              'Link'              ));              this              .              parseLinkHeader              (              res              .              headers              .              get              (              'Link'              ));              }));              }                      

Adjacent, open the src/app/home/habitation.component.ts file and import the Product interface:

                          import              {              Product              }              from              '../production'              ;                      

Next change the type of the products array as follows:

                          export              class              HomeComponent              implements              OnInit              ,              OnDestroy              {              products              :              Production              []              =              [];                      

Side by side alter the type of the HTTP response in the sendGetRequest() telephone call:

                          ngOnInit              ()              {              this              .              dataService              .              sendGetRequest              ().              pipe              (              takeUntil              (              this              .              destroy$              )).              subscribe              ((              res              :              HttpResponse              <              Production              []              >              )              =>              {              console              .              log              (              res              );              this              .              products              =              res              .              body              ;              })              }                      

Y'all also demand to do the same for the other firstPage(), previousPage(), nextPage() and lastPage() methods.

Pace 15 — Building and Deploying your Angular 11 Awarding to Firebase Hosting

In this footstep, we'll come across how to build and deploy our case awarding to Firebase hosting using the ng deploy command bachelor in Angular viii.3+.

We'll only encounter how to deploy the frontend application without the faux JSON server.

Angular CLI 8.3+ introduced a new ng deploy command that makes it more easier than before to deploy your Angular awarding using the deploy CLI builder assocaited with your project. There are many third-political party builders that implement deployment capabilities for different platforms. Yous can add any of them to your project by running the ng add command.

Later on adding a deployment package it will automatically update your workspace configuration (i.eastward the angular.json file) with a deploy section for the selected project. Yous can then utilise the ng deploy command to deploy that project.

Let's at present see that by example by deploying our project to Firebase hosting.

Head back to your command-line interface, make sure you are inside the root folder of your Athwart project and run the following control:

This will add the Firebase deployment capability to your project.

The control will also update the package.json of our project by adding this section:

                                                      "deploy"              :                                          {                                          "builder"              :                                          "@angular/burn down:deploy"              ,                                          "options"              :                                          {}                                          }                                                  

The CLI will prompt you to Paste authorisation code here: and will open your default web browser and enquire you to give Firebase CLI permissions to administer your Firebase account:

After you signin with the Google account associated with your Firebase account, you'll be given the authorization code:

Adjacent, y'all'll be prompted: Delight select a project: (Apply arrow keys or type to search). Yous should accept created a Firebase project before.

The CLI volition create the firebase.json and .firebaserc files and update the angular.json file appropriately.

Next, deploy your application to Firebase, using the post-obit command:

The control will produce an optimized build of your application (equivalent to the ng deploy --prod command), it will upload the production assets to Firebase hosting.

Conclusion

Throughout this Angular 11 tutorial, we've built a complete working Angular application example using the latest version.

Equally a epitomize, we've particularly seen past example how to set upwardly HttpClient and ship HTTP GET requests with parameters using the HttpClient.become() method, how to handle HTTP errors using the RxJS throwError() and catchError() operators, unsubscribe from RxJS Observables for the cancelled HTTP requests using the takeUntil() operator and retry failed requests with the retry() operator and finally how to deploy our awarding to Firebase hosting using the latest ng deploy characteristic available from Angular 8.three+.


careyamithe1971.blogspot.com

Source: https://www.techiediaries.com/angular-11-tutorial-example-rest-crud-http-get-httpclient/

0 Response to "Fire Observable Http Request Again if Condition Not Met"

Post a Comment

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel