Add emoji, GIFs and rich link previews to an Angular 7 chatroom

Add emoji, GIFs and rich link previews to an Angular 7 chatroom

In this tutorial, you'll learn three common features of Angular 7 chat chatroom and described how they can be implemented in a Chatkit powered application.

In this tutorial, you'll learn three common features of Angular 7 chat chatroom and described how they can be implemented in a Chatkit powered application.

Sometimes, sending only text just isn’t quite enough. This is where the ability to spice up a conversation with GIFs and emoji becomes invaluable. We can provide a richer user experience by adding the ability to search for and select emoji and animated GIFs directly in the chatroom.

An added feature we’ll be looking at in this tutorial is allowing users see what’s behind a link shared in the chatroom without clicking on it using rich link previews. This gives the user more information about a link so they can decide whether to click through or not. In the sections below, I’ll show you how to build out all these features into your Chatkit powered app.

Project setup

This tutorial is a continuation of the How to build a Chatroom with Angular 7 and Chatkit one, so you need to complete that first before moving on to this one. You can clone this GitHub repository and follow the instructions in the README file to get set up.

Prerequisites
  • Basic understanding of Angular and Node.js
  • Node.js (version 8 or later) and npm. Installation instructions are here.
Install additional dependencies

Run the command below from the client directory to install all the additional dependencies we’ll be needing in the course of building this application:

    npm install giphy-api skeleton-css @ctrl/ngx-emoji-mart angular-feather -S


Update the application styles

I made some changes to the CSS to account for the new features we’ll be building, so open up app.component.css and update the styles as follows:

    // client/src/app/app.component.css

    html {
      box-sizing: border-box;
    }

    *, *::before, *::after {
      box-sizing: inherit;
      margin: 0;
      padding: 0;
    }

    body {
      font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;
    }

    .App {
      width: 100vw;
      height: 100vh;
      display: flex;
      overflow: hidden;
    }

    ul {
      list-style: none;
    }

    .sidebar {
      flex-basis: 20%;
      background-color: #300d4f;
      color: #fff;
      padding: 5px 10px;
    }

    .sidebar input {
      color: #333;
    }

    .sidebar section {
      margin-bottom: 20px;
    }

    .sidebar h2 {
      margin-bottom: 10px;
    }

    .user-list li {
      margin-bottom: 10px;
      font-size: 16px;
      display: flex;
      align-items: center;
    }

    .presence {
      display: inline-block;
      width: 20px;
      height: 20px;
      background-color: #fff;
      margin-right: 10px;
      border-radius: 50%;
    }

    .presence.online {
      background-color: green;
    }

    .chat-window {
      flex-grow: 1;
      display: flex;
      flex-direction: column;
      justify-content: space-between;
      position: relative;
    }

    .chat-window > * {
      padding: 10px 20px;
    }

    .chat-header, .chat-footer {
      display: flex;
      align-items: center;
    }

    .chat-header {
      border-bottom: 1px solid #ccc;
    }

    .chat-session {
      height: calc(100vh - 108px);
      overflow-y: auto;
      position: relative;
    }

    .message-list {
      display: flex;
      flex-direction: column;
      justify-content: flex-end;
    }

    .user-message {
      margin-top: 10px;
    }

    .user-message span {
      display: block;
    }

    .user-id {
      font-weight: bold;
      margin-bottom: 3px;
    }

    .chat-footer {
      border-top: 1px solid #ccc;
    }

    .chat-footer form, .chat-footer input {
      width: 100%;
    }

    .chat-footer {
      padding: 0 !important;
    }

    .chat-footer form {
      display: flex;
      align-items: center;
      width: 100%;
    }

    .chat-footer input {
      height: 50px;
      flex-grow: 1;
      line-height: 35px;
      padding-left: 20px;
      border-radius: 0;
      border-top-left-radius: 0;
      border-top-right-radius: 0;
      border-bottom-left-radius: 0;
      border-bottom-right-radius: 0;
      border: none;
      font-size: 16px;
      color: #333;
      min-height: auto;
      overflow-y: hidden;
      resize: none;
      border-left: 1px solid #ccc;
    }

    .emoji-mart {
      position: fixed;
      bottom: 70px;
      right: 20px;
    }

    .chat-footer button {
      border: none;
      width: 50px;
      height: auto;
      padding: 0;
      margin-bottom: 0;
      display: flex;
      align-items: center;
      justify-content: center;
    }

    .toggle-emoji svg {
      width: 28px;
      height: 28px;
    }

    .giphy-search {
      position: fixed;
      bottom: 70px;
      right: 20px;
      width: 300px;
      height: 300px;
      overflow-y: auto;
      border: 1px solid #ccc;
      border-radius: 4px;
      background-color: #fff;
    }

    .giphy-search input {
      width: 100%;
    }

    img {
      max-width: 100%;
    }

    .gif-result img {
      cursor: pointer;
    }

Next, we need to tell the Angular CLI of some of the other styles our application needs. These styles are from the dependencies we just installed. Open up angular.json and change the styles property as shown below. By doing this, you’re specifying that the referenced styles be included in your application bundle.

    // client/angular.json

    "styles": [
      "src/styles.css",
      "node_modules/@ctrl/ngx-emoji-mart/picker.css",
      "node_modules/skeleton-css/css/skeleton.css",
      "node_modules/skeleton-css/css/normalize.css"
    ]

Start the application

If you haven’t already, install angular-cli globally by running npm install -g @angular/cli in the terminal, then cd to your client directory and run ng serve to build and serve the app at http://localhost:4200. Don’t forget to start your Node.js server by running node server.js from the project root.

Set up the app icons

We’ll be making use of Feather Icons for our iconography needs via the angular-feather package. Before we can use it in our template files, a couple of additional steps are needed.

First, run the command below from the client directory to generate a module to host the icons we’ll import:

    ng generate module icons


The command above should create a new icons.module.ts file in client/src/app/icons/icons.module.ts. Open up the file, and change it to look like this:

    // client/src/app/icons/icons.module.ts

    import { NgModule } from '@angular/core';
    import { IconSmile } from 'angular-feather';

    const icons = [
      IconSmile,
    ];

    @NgModule({
      exports: icons
    })
    export class IconsModule { }

We’re making use of the smile icon in the emoji picker toggle, so we’ve imported it above. Finally, we need to import IconsModule in our app.module.ts and declare it in the imports array as shown below.

    // client/src/app/app.module.ts

    // [..]
    import { IconsModule } from './icons/icons.module';

    @NgModule({
      declarations: [
        AppComponent,
      ],
      imports: [
        BrowserModule,
        FormsModule,
        IconsModule,
      ],
      providers: [],
      bootstrap: [AppComponent]
    })

    export class AppModule { }

Now, we’ll be able to use the smile icon in our templates like this <i-smile></i-smile> as you’ll see in the next section.

Add an emoji picker to the room

It is important to provide easy access to emojis in a chat app, and the accepted way of doing so is using an emoji picker where users can easily search for and add an emoji to their message. We’ll be making use of the emoji-mart package to build this feature into our app. Although originally built for React apps, this package has been ported for use in Angular applications as well.

First, let’s add a button that can be used to toggle the emoji picker. Open up app.component.html and change it to look like this:

    // client/src/app/app.component.html

    <div class="App">
      <!-- [..] -->

      <main class="chat-window">
        <!-- [..] -->
        <footer class="chat-footer">
          <form (ngSubmit)='sendMessage()'>
            <button
              type="button"
              class="toggle-emoji"
              (click)="toggleEmojiPicker()"
              >
              <i-smile></i-smile>
            </button>
            <input placeholder="Type a message. Hit Enter to send" type="text"
            name="message" [(ngModel)]="message">
          </form>
        </footer>
      </main>
    </div>

Next, update the app.component.ts as follows:

    // client/src/app/app.component.ts

    // [..]
    export class AppComponent {
      // [..]
      showEmojiPicker = false;

      // [..]

      toggleEmojiPicker() {
        this.showEmojiPicker = !this.showEmojiPicker;
      }

      // [..]
    }

The app should look like this now, and the button will toggle the showEmojiPicker flag to true or false when clicked via the toggleEmojiPicker() method.

The next step is to toggle the visibility of the emoji picker based on the value of showEmojiPicker. To use the emoji picker, we need to import the PickerModule in app.module.ts and declare it in the imports array:

    // client/src/app/app.module.ts

    // [..]
    import { PickerModule } from '@ctrl/ngx-emoji-mart';

    @NgModule({
      declarations: [
        AppComponent,
      ],
      imports: [
        BrowserModule,
        FormsModule,
        IconsModule,
        PickerModule,
      ],
      providers: [],
      bootstrap: [AppComponent]
    })

    export class AppModule { }

Then use the emoji mart component in app.component.html:

    // client/src/app/app.component.html

    <div class="App">
      <!-- [..] -->

      <main class="chat-window">
        <!-- [..] -->
        <section class="chat-session">
          <!-- [..] -->

          <emoji-mart class="emoji-mart" set="emojione" (emojiSelect)="addEmoji($event)" *ngIf="showEmojiPicker" title="Pick your emoji…"></emoji-mart>
        </section>

      </main>
    </div>

Now, you should be able to toggle the emoji picker by clicking the smile icon.

The next step is make it possible to add an emoji to a message by selecting it in the emoji picker. Notice the (emojiSelect) event on the emoji mart component in app.component.html. It is triggered when an emoji is selected in the picker, and details about the event is passed to the addEmoji() method which updates the message input with the selected emoji.

Create the addEmoji() method in app.component.ts below toggleEmojiPicker():

    // client/src/app/app.component.ts

    // [..]
    export class AppComponent {
      // [..]

      toggleEmojiPicker() {
        this.showEmojiPicker = !this.showEmojiPicker;
      }

      addEmoji(event) {
        const { message } = this;
        const text = `${message}${event.emoji.native}`;

        this.message = text;
        this.showEmojiPicker = false;
      }

      // [..]
    }

You can try it out by selecting an emoji from the emoji picker. It should work as shown below:

Add rich link previews with Microlink

The next feature we’ll add to this app is the ability to show a preview of web content like articles, pages, and YouTube videos shared in the application. We’ll be achieving this using the Microlink package which can be used as an npm package or linked via a CDN.

As I didn’t have much success with getting the npm package to compile, we’ll make use of the provided CDN for this tutorial. Reference the microlink script in client/src/index.html as shown below:

    <!-- client/src/index.html -->

    <!doctype html>
    <html lang="en">
    <head>
      <meta charset="utf-8">
      <title>AngularChatroom</title>
      <base href="/">

      <meta name="viewport" content="width=device-width, initial-scale=1">
      <link rel="icon" type="image/x-icon" href="favicon.ico">
    </head>
    <body>
      <app-root></app-root>

      <script src="//cdn.jsdelivr.net/npm/@microlink/[email protected]/umd/microlink.min.js"></script>
    </body>
    </html>

Following that, we need to detect the presence of a URL in a message and display the link appropriately in the rendered message. To do so, we’ll update the onMessage hook in addUser() as follows:

    // client/src/app/app.component.ts

    hooks: {
      onMessage: message => {
        let { text } = message;
        const urlMatches = message.text.match(/\b(http|https)?:\/\/\S+/gi) || [];

        function insertTextAtIndices(text, obj) {
          return text.replace(/./g, function(character, index) {
            return obj[index] ? obj[index] + character : character;
          });
        }

        urlMatches.forEach(link => {
          const startIndex = text.indexOf(link);
          const endIndex = startIndex + link.length;
          text = insertTextAtIndices(text, {
            [startIndex]: `<a href="${link}" target="_blank" rel="noopener noreferrer" class="embedded-link">`,
            [endIndex]: '</a>',
          });
        });

        this.messages.push({ ...message, text, url_matches: urlMatches, });
      },
      // [..]
    }

Here, we’re matching the message text against a regular expressions and returning an array of URLs found in the message text or an empty array if no links are present in the message. Next, each URL in the array is wrapped in an anchor tag with the help of the insertTextAtIndices() function. Finally, the array of URLs found in the message text are placed in the url_matches property of the message object.

Next, let’s render an anchor tag for each link present in the url_matches and give it a class of .link-preview so that we can target those anchor tags and replace them with rich link previews using microlink. Update app.component.html as follows:

    // client/src/app/app.component.html

    <div class="App">
      <!-- [..] -->

      <main class="chat-window">
        <!-- [..] -->
        <section class="chat-session">
          <ul class="message-list">
            <li class="user-message" *ngFor="let message of messages">
              <span class="user-id">{{ message.senderId }}</span>
              <span [innerHTML]="message.text"></span>
              <a *ngFor="let link of message.url_matches" href="{{ link }}"
                class="link-preview">{{
                link }}</a>
            </li>
          </ul>
          <emoji-mart class="emoji-mart" set="emojione" (emojiSelect)="addEmoji($event)" *ngIf="showEmojiPicker" title="Pick your emoji…"></emoji-mart>

        </section>
        <!-- [..] -->
      </main>
    </div>

Then update app.component.ts as follows:

    // client/src/app/app.component.ts

    import { Component, AfterViewChecked } from '@angular/core';
    import Chatkit from '@pusher/chatkit-client';
    import axios from 'axios';
    declare const microlink;

    // [..]

    export class AppComponent implements AfterViewChecked {
      // [..]

      ngAfterViewChecked() {
        microlink('.link-preview');
      }

      toggleEmojiPicker() {
        this.showEmojiPicker = !this.showEmojiPicker;
      }

      // [..]

    }

At this point, you be able to view a minimal preview for each link shared in the chatroom.

Share GIFs in the chatroom with Giphy

The final feature for this tutorial involves building out the ability to search for and share GIFs right from within the chat app. We’ll be making use of the Giphy API via the giphy-api package which has already be installed as a dependency.

The user will be able to toggle a GIF picker, search for a GIF by entering a search term, and view the results in the picker. Once a GIF is clicked, it will be sent to the room as an image attachment and rendered on the screen.

Update your app.component.html file to look like this:

    // client/src/app/app.component.html

    <div class="App">
      <!-- [..] -->

      <main class="chat-window">
        <!-- [..] -->
        <section class="chat-session">
          <ul class="message-list">
            <li class="user-message" *ngFor="let message of messages">q
              <span class="user-id">{{ message.senderId }}</span>
              <span [innerHTML]="message.text"></span>
              <img *ngIf="message.attachment"
                class="image-attachment"
                src="{{ message.attachment.link }}"
                alt="{{ message.attachment.name }}"
                />
              <a *ngFor="let link of message.url_matches" href="{{ link }}"
                class="link-preview">{{
                link }}</a>
            </li>
          </ul>
          <emoji-mart class="emoji-mart" set="emojione" (emojiSelect)="addEmoji($event)" *ngIf="showEmojiPicker" title="Pick your emoji…"></emoji-mart>
          <div *ngIf="showGiphySearch" class="giphy-search">
            <form (ngSubmit)="searchGiphy()">
              <input type="text" placeholder="Search for a GIF" name="giphy" [(ngModel)]="giphySearchTerm">
            </form>
            <ul class="search-results">
              <li class="gif-result" *ngFor="let result of giphyResults">
                <img src="{{ result.images.downsized_large.url }}"
                     (click)="sendGif(result.title, result.images.original.url)">
              </li>
            </ul>
          </div>
        </section>
        <footer class="chat-footer">
          <form (ngSubmit)='sendMessage()'>
            <!-- [..] -->
            <button type="button" class="toggle-giphy"
              (click)="toggleGiphySearch()">GIF</button>
          </form>
        </footer>
      </main>
    </div>

Then update app.component.ts as follows:

    // client/src/app/app.component.ts

    import { Component, AfterViewChecked } from '@angular/core';
    import Chatkit from '@pusher/chatkit-client';
    import axios from 'axios';
    import Giphy from 'giphy-api';
    declare const microlink;

    // [..]

    export class AppComponent implements AfterViewChecked {
      // [..]
      showGiphySearch = false;
      giphySearchTerm = '';
      giphyResults = [];

      // [..]

      ngAfterViewChecked() {
        microlink('.link-preview');
      }

      searchGiphy() {
        const giphy = Giphy();
        const searchTerm = this.giphySearchTerm;
        giphy.search(searchTerm)
          .then(res => {
            console.log(res);
            this.giphyResults = res.data;
          })
          .catch(console.error);
      }

      sendGif(title, url) {
        const { currentUser } = this;
        currentUser.sendMessage({
          text: title,
          roomId: '<your room id>',
          attachment: {
            link: url,
            type: 'image',
          }
        }).catch(console.error);
        this.showGiphySearch = false;
      }

      toggleGiphySearch() {
        this.showGiphySearch = !this.showGiphySearch;
      }

      // [..]
    }

The GIF button toggles the visibility of the GIF picker via the toggleGiphySearch() method. Once the user enters a search term and submits the form, the searchGiphy() method is triggered and the results are stored in giphyResults which renders them in the .search-results list. The user can scroll through the list and select their preferred GIF. By clicking on the image, the sendGif() method is triggered, and the animated GIF is rendered in the chat for all the participants.

Here’s a GIF of what the above steps look like in practice. Before you test this out, make sure to replace <your room id> with the appropriate value from your Chatkit instance dashboard.

Wrap up

In this tutorial, I’ve explored three common features of chat applications and described how they can be implemented in a Chatkit powered application. First, we added an emoji picker so that users can quickly search for and include an emoji in their message. Next, we provided rich link previews for links shared in the chatroom, and finally, we added an option to search a library of animated GIFs and share them in the chatroom.

The source code for this project can be found here.

How to Show Image Preview with Reactive Forms in Angular 8

How to Show Image Preview with Reactive Forms in Angular 8

Today in this tutorial, we are going to understand how to show image preview before uploading to the server in Angular app. We will take the help of the HTML input element to upload the selected image.

I have come across a straightforward method through which we can show the image preview to the user before uploading image to the server.We will also learn to apply validation for uploading only images using HTML5 new FileReader() api.

Table of contents

  1. Prerequisite
  2. Set up Angular 8 App
  3. Import ReactiveFormsModule in App Module
  4. Set up Image Preview Component
  5. Image Preview Before Uploading in Angular 8
  6. Conclusion

Prerequisite

In order to show you Angular 8 image preview demo, you must install Node.js and Angular CLI in your machine. If you are beginner then follow this tutorial: Set up Node JS

Run command to set up Angular CLI globally:

npm install @angular/cli -g

Set up Angular 8 App

Enter command and hit enter to set up Angular 8 project:

ng new angular-image-preview
? Would you like to add Angular routing? No
? Which stylesheet format would you like to use? CSS


cd angular-image-preview

Run command to create component to manage the file preview in Angular 8.

ng g c fileUpload

CREATE src/app/file-upload/file-upload.component.css (0 bytes) CREATE src/app/file-upload/file-upload.component.html (26 bytes) CREATE src/app/file-upload/file-upload.component.spec.ts (657 bytes) CREATE src/app/file-upload/file-upload.component.ts (288 bytes)

Import ReactiveFormsModule in App Module

Import ReactiveFormsModule service in app.module.ts file.

import { ReactiveFormsModule } from '@angular/forms';

@NgModule({
imports: [
ReactiveFormsModule
],
})

export class AppModule { }

Set up Image Preview Component

In the next step, go to file.upload.component.html file and include the following code.

<form [formGroup]="uploadForm" (ngSubmit)="submit()">
<!-- Select File -->
<input type="file" accept="image/*" (change)="showPreview($event)" />

<!-- Image Preview -->
<div class="imagePreview" *ngIf="imageURL && imageURL !== ''">
<img [src]="imageURL" [alt]="uploadForm.value.name">
</div>

<!-- Assign Image Alt -->
<input formControlName="name" placeholder="Enter name">

<button type="submit">Submit</button>
</form>

The HTML’s <input type="file"> element is used to deal with files. To accept only image files we are using HTML5’s accept attribute and passed "Image/" attribute in it. The accept attribute allows user to pick the file through input dialog box, you can allow various file types with accept attribute.

Below are the file extension can be set using accept attribute

<input accept="file_type | audio/ | video/* | image/* | media_type">

We declared the (change)="..." event, so whenever any change occurs in the value, the image data will be updated as per the file picked by the user.

To show the image preview in Angular 8, we declared the img HTML tag and bind the src tag to the variable. We will assign the image URL to the src variable using the new FileReader() method.

Image Preview Before Uploading in Angular 8

Go to file-upload.component.ts file and add the given below code inside of it.

import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup } from "@angular/forms";

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

export class FileUploadComponent implements OnInit {
imageURL: string;
uploadForm: FormGroup;

constructor(public fb: FormBuilder) {
// Reactive Form
this.uploadForm = this.fb.group({
avatar: [null],
name: ['']
})
}

ngOnInit(): void { }

// Image Preview
showPreview(event) {
const file = (event.target as HTMLInputElement).files[0];
this.uploadForm.patchValue({
avatar: file
});
this.uploadForm.get('avatar').updateValueAndValidity()

// File Preview
const reader = new FileReader();
reader.onload = () =&gt; {
  this.imageURL = reader.result as string;
}
reader.readAsDataURL(file)

}

// Submit Form
submit() {
console.log(this.uploadForm.value)
}

}

  • We are using Reactive Forms approach within in Angular 8 to handle image upload. Now we initialized it by assigning FormGroup service to uploadForm at the beginning.
  • The imageURL variable is used to pass the base64 URL to the img element.
  • Inside the showPreview function, we passed the JavaScript default event object as an argument to extract the image file. Now, here, we need to explicitly define the HTMLInputElement type because Angular doesn’t know that the file type we are targeting exists or not. It might through an error. (event.target as HTMLInputElement)
  • As you can see, we stored the name and avatar value in the form control already. For the avatar property, we won’t bind the avatar value to the formControlName with the HTML element as we already did for the name property. Therefore we will be using Angular 8’s patchValue({ }) service to bind the image value
  • The updateValueAndValidity() method informs Angular whenever the user makes any change. Technically this method tells Angular and Recalculates the value and validation status of the control.
  • Then we will convert image to dataURI by using the FileReader API. Finally, we will set the dataURI to imageURL variable, then pick the image from your device, and you will see the image preview in Angular 8 application.

Conclusion

Finally, we are done with Angular 8 Image Preview tutorial. I hope you loved this tutorial, please share it with others.

Further reading

☞ What’s New in Angular 8.0

☞ To become an Outstanding AngularJs Developer - part 1

☞ To become an Outstanding AngularJs Developer - part 2

☞ To become an effective Angular developer, you need to learn 19 things in this article

☞ Angular 8 (formerly Angular 2) - The Complete Guide

Manage reactive form controls with form groups in Angular 8

Angular 8 HttpClient & Http Tutorial – Build and Consume RESTful API


This post was originally published here

Angular 8 File Upload Tutorial With Example | Angular Image Upload

Angular 8 File Upload Tutorial With Example | Angular Image Upload

Uploading images is a common requirement in Angular applications and this article will show you how easy it is to solve that problem in angular 8.

Angular 8 File Upload Tutorial With Example | Angular Image Upload is today’s topic. If you are new to Angular 8, then check out ** **Angular 8 Tutorial.In this Angular Image Upload demo, we will use the ng2-file-upload library to upload a file to the node server. We use Node.js as a backend server. We install Angular using Angular 8 CLI and then start working on this Angular File Upload demo. For handling the uploaded files at the backend server, we use **the multer **library.

Content Overview

  • 1 Angular 8 File Upload Tutorial
  • 2 #Install rxjs-compat library
  • 3 #Install Bootstrap 4
  • 4 #Install an ng-file-upload library
  • 5 #Create Node.js backend
Angular 8 File Upload Tutorial

Now, set up the angular project using the following command.

ng new ng8fileupload

Now, spin up the angular app using the following command.

ng serve --open

#Install rxjs-compat library

So, to fill the gap between Angular 8 and third-party packages, we need to install the rxjs-compat library. That is it.

npm install rxjs-compat --save

Now, you will not get any error regarding any rxjs observables.

#Install Bootstrap 4

Go to your terminal and type the following command.

npm install bootstrap --save

Now, include that above file inside the **angular.json **file.

"styles": [
   "src/styles.css",
   "./node_modules/bootstrap/dist/css/bootstrap.min.css"
 ],

It will include the library in Angular application.

#Install an ng-file-upload library

Type the following command to install the library.

npm install ng2-file-upload --save

Now, write a following code inside **an app.module.ts **file.

// app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FileSelectDirective } from 'ng2-file-upload';
import { FormsModule } from '@angular/forms';

import { AppComponent } from './app.component';

@NgModule({
  declarations: [
    AppComponent,
    FileSelectDirective
  ],
  imports: [
    BrowserModule,
    FormsModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

We have imported the **FileSelectDirective **from ng2-file-upload.

Also, we need to import the FormsModule. We need FormsModule because we need to write the file upload component.

Now, write the following code inside an **app.component.ts **file.

// app.component.ts

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

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

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
  title = 'ng8fileupload';
  public uploader: FileUploader = new FileUploader({ url: URL, itemAlias: 'photo' });
  ngOnInit() {
    this.uploader.onAfterAddingFile = (file) => { file.withCredentials = false; };
    this.uploader.onCompleteItem = (item: any, response: any, status: any, headers: any) => {
         console.log('ImageUpload:uploaded:', item, status, response);
         alert('File uploaded successfully');
    };
 }
}

n the above code, we have imported **FileUploader **and **FileSelectDirective **from ng2-file-upload.

Also, we have defined the backend API URL, which is http://localhost:4000/api/upload.

We will create a backend server in Node.js and then send a POST request to the server.

So, here we have used the Angular Component lifecycle. The function is ngOnInit().

We have written the file upload code inside the ngOnInit function.

Now, the only thing remaining is written the HTML code for the file upload component.

Write the following piece code inside the **app.component.html **file.


  
  <button type="button" class="btn btn-success btn-s" 
    (click)="uploader.uploadAll()" 
    [disabled]="!uploader.getNotUploadedItems().length" >
        Upload an Image
  


Now, go to the http://localhost:4200/** **URL and see the output.

Now the only thing remaining is to create a backend in Node.js.

#Create Node.js backend

First, install the following node modules.

npm install express multer body-parser dotenv --save

Install nodemon as a dev dependency.

npm install nodemon --save-dev

Create a new directory inside root of angular project called uploads.

Okay, now create one file in the angular project root folder called server.js.

Write the following piece code inside the **server.js **file.

// server.js

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

const DIR = './uploads';
 
let storage = multer.diskStorage({
    destination: (req, file, cb) => {
      cb(null, DIR);
    },
    filename: (req, file, cb) => {
      cb(null, file.fieldname + '-' + Date.now() + '.' + path.extname(file.originalname));
    }
});
let upload = multer({storage: storage});

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
 
app.use(function (req, res, next) {
  res.setHeader('Access-Control-Allow-Origin', 'http://localhost:4200');
  res.setHeader('Access-Control-Allow-Methods', 'POST');
  res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type');
  res.setHeader('Access-Control-Allow-Credentials', true);
  next();
});
 
app.get('/api', function (req, res) {
  res.end('file catcher example');
});
 
app.post('/api/upload',upload.single('photo'), function (req, res) {
    if (!req.file) {
        console.log("No file received");
        return res.send({
          success: false
        });
    
      } else {
        console.log('file received');
        return res.send({
          success: true
        })
      }
});
 
const PORT = process.env.PORT || 4000;
 
app.listen(PORT, function () {
  console.log('Node.js server is running on port ' + PORT);
});

First, we have used process.env. Working with environment variables is a great way to configure different configurations of your Node.js application.

If the environment variable PORT is defined inside the .env file, then it will take that variable’s value; otherwise, it will pick the value of by default, and in our case, it is 4000. So node.js will spin up on the port 4000.

We have imported the **multer **library. It is the node.js compatible library to handling file or image handling in the node.js.

We can store the file using the multer’s file storage function.

When the HTTP POST request of the file is coming to the node.js server, then first we have used the body-parser module which parses the request data and then go to the multer function and extract the file from the request and add the timestamp to the filename and save the file inside the **uploads **directory. We have already defined the directory.

The final step is to start the node.js server using the following code.

nodemon server

Now, go to the frontend and try to upload a file. I have tried to upload an image, and it is successfully uploaded. You can see the alert() on the frontend.

This is the primary example of Image Upload in Angular 8. If you want to resize the image using the node.js, then check out my Node.js image resize tutorial.

Also, see the **uploads **folder to see if the image is saved or not.

You can find more options on ng2-file-upload official documentation.

Finally, **Angular 8 File Upload Tutorial With Example | Angular Image Upload **is over. Thanks for taking.

Angular Tutorial - Learn Angular from Scratch

Angular Tutorial - Learn Angular from Scratch

Angular Tutorial - Learn Angular from Scratch: This course is for beginners who are curious on how to get started with Angular. In this course you will learn how to download, install and play around with Angular. We teach you the main components of Angular, so that you can get up and running with it asap. You will learn now to start building applications with Angular.

This course is for beginners who are curious on how to get started with Angular. In this course you will learn how to download, install and play around with Angular. We teach you the main components of Angular, so that you can get up and running with it asap. You will learn now to start building applications with Angular.

Learning Angular can be a daunting experience that's why this course was created; to give you an easier learning experience with it.

What am I going to get from this course?

  • You will learn the mayor fundamentals of Angular
  • You will learn how to get up and running with Angular
  • You will learn to create Applications using Angular 5 and beyond

What you'll learn

  • You will learn the mayor fundamentals of Angular
  • You will learn how to get up and running with Angular
  • You will learn to create Applications using Angular 5 and beyond