Learn how to use RxJS in Angular

Learn how to use RxJS in Angular

After a few years of Angular frontend development with heavy use of RxJS I decided to put some of my personal key learnings into a concise writeup.

In this article, I’m assuming that you already have some basic understanding of how Observable-streams, as well as the different Subject-types work. If so, this may hopefully help you master the most common use-cases of RxJS in Angular.

Component Inputs

As the values of your component inputs change over time, you may want to do something with that data inside your component. So what you usually do is implement the NgOnChanges method to react to those changes. Now this gets a bit fuzzy as soon as you depend on other asynchronous data, which is exactly where RxJS comes in. Unfortunately, it is currently not natively supported for component inputs to be streamed.

Therefore, whenever I need the power of RxJS on changing component inputs, I use this pattern:

@Input() public amount: number;
public amount$ = new Subject();
public ngOnChanges(changes: SimpleChanges): void {
  if (changes.amount && changes.amount.currentValue !== undefined) {
    this.amount$.next(changes.amount.currentValue);
  }
}

The !== undefined is only needed in case the new input value could be evaluated to false according to the laws of JavaScript.

Button Clicks

Let’s say you had some RxJS-based counter going and you wanted to reset this counter by clicking a reset-button. The most straightforward way (I know) to accomplish this, would be, to create a new `onReset<div class="section-inner sectionLayout--insetColumn" Subject which you can then weave into your counter-stream setup.

<button (click)="onReset$.next()">Reset</button>

Http Requests

For the basic setup of data services, you can follow the Angular Guide.
 But usually, there are use cases where retrieving data is not as simple as that. Many times you rely on other asynchronous data. So the mental model for that could be:

As soon as I get data X, I want to load data Y (which relates X)

Many times you could extend the above statement with

and if there still is an open Y-request (related to a previous X), I want to cancel that one.

If that’s what you want to achieve, the switchMap-operator is what you’re looking for. Consider the following example for retrieving the bookmarks of our current user.

public bookmarks$ = this.currentUser$.pipe(
  switchMap(user => this.bookmarksService.getBookmarks(user.id)),
);

Async Pipe

Angular includes a very useful async-pipe, which makes it easy to consume your observable streams in-template. So instead of subscribing within your TypeScript component and assigning the value to a public property, you can just use the async-pipe to retrieve your asynchronous values.

<ul>
  <li *ngFor="let bookmark of bookmarks$|async">{{bookmark}}</li>
</ul>

Sharing Expensive Data

Using the techniques mentioned above, you may go ahead and subscribe multiple times to your bookmarks$ stream, using the async-pipe. When having a look at your network console, you will soon realize, that multiple requests are being done. That’s not what we want. Instead, we want to share the response with whomever is interested in it.

There are multiple ways to achieve this. One of them being the publishReplay-operator, which publishes the source stream as a ReplaySubject, followed by the refCount-operator, which handles (un-) subscribing as long as there’s at least one listener.

public bookmarks$ = this.currentUser$.pipe(
  switchMap(user => this.bookmarksService.getBookmarks(user.id)),
  publishReplay(1),
  refCount(),
);

Unsubscribing

On to the last point of this post. If you always use the async-pipe, there’s no need to worry about unsubscribing, as the pipe handles this by itself. So, of course, it makes a lot of sense to use it whenever possible. But there may be cases where you need to manually subscribe to observable-streams. In those cases, it is important, that you properly unsubscribe, or you will experience memory leaks. Using the takeUntil-operator was the cleanest way I found, to accomplish this.

The preceding setup in your component looks like this:

private unsubscribe$ = new Subject();
public ngOnDestroy(): void {
  this.unsubscribe$.next();
  this.unsubscribe$.complete();
}

So on any stream that needs to be closed, you can just use the takeUntil-operator right before calling subscribe and your subscriptions will be closed as soon as your component is about to be destroyed.

this.bookmarks$
  .pipe(takeUntil(this.unsubscribe$))
  .subscribe(bookmarks => {
    // do something
  });

I really hope this helped some of you to get started in the world of Angular and RxJS, as it can be quite a bit intimidating at first.

Any questions and suggestions are very welcome. More content will follow.

30s ad

Learn Angular 2 from Beginner to Advanced

Angular 2 Firebase - Build a Web App with Typescript

Angular 2 Demystified

Master Angular 2 - The No Nonsense Course

Complete Angular 7 - Ultimate Guide - with Real World App

What are the best alternatives for angular js?

<img src="https://moriohcdn.b-cdn.net/193902114c.png">There are numerous frameworks and libraries used across the globe. If not angular, there are platforms like React, Vue, Aurelia and so on for app development.

There are numerous frameworks and libraries used across the globe. If not angular, there are platforms like React, Vue, Aurelia and so on for app development.

Angular 8 Node & Express JS File Upload

Angular 8 Node & Express JS File Upload

In this Angular 8 and Node.js tutorial, we are going to look at how to upload files on the Node server. To create Angular image upload component, we will be using Angular 8 front-end framework along with ng2-file-upload NPM package; It’s an easy to use Angular directives for uploading the files.

In this Angular 8 and Node.js tutorial, we are going to look at how to upload files on the Node server. To create Angular image upload component, we will be using Angular 8 front-end framework along with ng2-file-upload NPM package; It’s an easy to use Angular directives for uploading the files.

We are also going to take the help of Node.js to create the backend server for Image or File uploading demo. Initially, we’ll set up an Angular 8 web app from scratch using Angular CLI. You must have Node.js and Angular CLI installed in your system.

We’ll create the local server using Node.js and multer middleware. Multer is a node.js middleware for handling multipart/form-data, which is primarily used for uploading files. Once we are done setting up front-end and backend for our File uploading demo then, we’ll understand step by step how to configure file uploading in Angular 8 app using Node server.

Prerequisite

In order to show you Angular 8 File upload demo, you must have Node.js and Angular CLI installed in your system. If not then check out this tutorial: Set up Node JS

Run following command to install Angular CLI:

npm install @angular/cli -g

Install Angular 8 App

Run command to install Angular 8 project:

ng new angular-node-file-upload

# ? Would you like to add Angular routing? No
# ? Which stylesheet format would you like to use? CSS
cd angular-node-file-upload

Show Alert Messages When File Uploaded

We are going to install and configure ngx-toastr an NPM package which helps in showing the alert message when the file is uploaded on the node server.

npm install ngx-toastr --save

The ngx-toastr NPM module requires @angular/animations dependency:

npm install @angular/animations --save

Then, add the ngx-toastr CSS in angular.json file:

"styles": [
    "src/styles.css",
    "node_modules/ngx-toastr/toastr.css"
]

Import BrowserAnimationsModule and ToastrModule in app.module.ts file:

import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { ToastrModule } from 'ngx-toastr';
 
@NgModule({
  imports: [
    CommonModule,
    BrowserAnimationsModule, // required animations module
    ToastrModule.forRoot() // ToastrModule added
  ]
})

export class AppModule { }

Install & Configure ng-file-upload Directive

In this step, we’ll Install and configure ng-file-upload library in Angular 8 app. Run command to install ng-file-upload library.

npm install ng2-file-upload

Once the ng2-file-upload directive is installed, then import the FileSelectDirective and FormsModule in app.module.ts. We need FormsModule service so that we can create the file uploading component in Angular.

import { FileSelectDirective } from 'ng2-file-upload';
import { FormsModule } from '@angular/forms';

@NgModule({
  declarations: [
    FileSelectDirective
  ],
  imports: [
    FormsModule
  ]
})

export class AppModule { }

Setting Up Node Backend for File Upload Demo

To upload the file on the server, we need to set up a separate backend. In this tutorial, we will be using Node & Express js to create server locally along with multer, express js, body-parser, and dotenv libraries.

Run command to create backend folder in Angular app’s root directory:

mkdir backend && cd backend

In the next step, create a specific package.json file.

npm init

Run command to install required dependencies:

npm install express cors body-parser multer dotenv --save

In order to get rid from starting the server again and again, install nodemon NPM package. Use –-save-dev along with the npm command to register in the devDependencies array. It will make it available for development purpose only.

npm install nodemon --save-dev

Have a look at final pacakge.json file for file upload demo backend:

{
  "name": "angular-node-file-upload",
  "version": "1.0.0",
  "description": "Angualr 8 file upload demo app",
  "main": "server.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "node server.js"
  },
  "author": "Digamber Rawat",
  "license": "ISC",
  "dependencies": {
    "body-parser": "^1.19.0",
    "cors": "^2.8.5",
    "dotenv": "^8.0.0",
    "express": "^4.17.1",
    "multer": "^1.4.1"
  },
  "devDependencies": {
    "nodemon": "^1.19.1"
  }
}

Create a file by the name of server.js inside backend folder:

Configure Server.js

To configure our backend we need to create a server.js file. In this file we’ll keep our backend server’s settings.

touch server.js

Now, paste the following code in backend > server.js file:

const express = require('express'),
  path = require('path'),
  cors = require('cors'),
  multer = require('multer'),
  bodyParser = require('body-parser');

// File upload settings  
const PATH = './uploads';

let storage = multer.diskStorage({
  destination: (req, file, cb) => {
    cb(null, PATH);
  },
  filename: (req, file, cb) => {
    cb(null, file.fieldname + '-' + Date.now())
  }
});

let upload = multer({
  storage: storage
});

// Express settings
const app = express();
app.use(cors());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
  extended: false
}));

app.get('/api', function (req, res) {
  res.end('File catcher');
});

// POST File
app.post('/api/upload', upload.single('image'), function (req, res) {
  if (!req.file) {
    console.log("No file is available!");
    return res.send({
      success: false
    });

  } else {
    console.log('File is available!');
    return res.send({
      success: true
    })
  }
});

// Create PORT
const PORT = process.env.PORT || 8080;
const server = app.listen(PORT, () => {
  console.log('Connected to port ' + PORT)
})

// Find 404 and hand over to error handler
app.use((req, res, next) => {
  next(createError(404));
});

// error handler
app.use(function (err, req, res, next) {
  console.error(err.message);
  if (!err.statusCode) err.statusCode = 500;
  res.status(err.statusCode).send(err.message);
});

Now, while staying in the backend folder run the below command to start the backend server:

nodemon server.js

If everything goes fine then you’ll get the following output:

[nodemon] 1.19.1
[nodemon] to restart at any time, enter `rs`
[nodemon] watching: *.*
[nodemon] starting `node server.js`
Connected to port 8080

Create Angular 8 File Upload Component

In this last step, we are going to create a file upload component in Angular 8 app using Express js API.

Get into the app.component.ts file and include the following code:

import { Component, OnInit } from '@angular/core';
import { FileUploader } from 'ng2-file-upload/ng2-file-upload';
import { ToastrService } from 'ngx-toastr';

const URL = 'http://localhost:8080/api/upload';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})

export class AppComponent implements OnInit {
  public uploader: FileUploader = new FileUploader({
    url: URL,
    itemAlias: 'image'
  });

  constructor(private toastr: ToastrService) { }

  ngOnInit() {
    this.uploader.onAfterAddingFile = (file) => {
      file.withCredentials = false;
    };
    this.uploader.onCompleteItem = (item: any, status: any) => {
      console.log('Uploaded File Details:', item);
      this.toastr.success('File successfully uploaded!');
    };
  }

}

Go to app.component.html file and add the given below code:

<div class="wrapper">
  <h2>Angular Image Upload Demo</h2>

  <div class="file-upload">
    <input type="file" name="image" ng2FileSelect [uploader]="uploader" accept="image/x-png,image/gif,image/jpeg" />
    <button type="button" (click)="uploader.uploadAll()" [disabled]="!uploader.getNotUploadedItems().length">
      Upload
    </button>
  </div>

</div>

Now, It’s time to start the Angular 8 app to check out the File upload demo in the browser. Run the following command:

ng serve --open

Make sure your NODE server must be running to manage the backend.

When you upload the image from front-end you’ll see your image files are saving inside the backend > uploads folder.

Conclusion

In this Angular 8 tutorial, we barely scratched the surface related to file uploading in a Node application. There are various other methods available on the internet through which you can achieve file uploading task quickly. However, this tutorial is suitable for beginners developers. I hope this tutorial will surely help and you if you liked this tutorial, please consider sharing it with others.

Angular JS Development Company

If you’re finding AngularJS Development Company for consultation or Development, your search ends here at Data EximIT 

🔗 Click here to know more: AngularJS Development