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.

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.

How to Use Cookies in Angular for Storing user’s Credentials

How to Use Cookies in Angular for Storing user’s Credentials

In this post, I will be explaining about using Cookies in Angular for Storing user’s Credentials

By using cookies we are going to store the user's login data, if the user's credentials are valid, then it will be directed to the Dashboard page.

In this post, I will be explaining about Angular cookies. So what is a cookie? Cookies are like a small package of information that is stored by the user’s browser. Cookies persist across multiple requests and browser sessions that should be set so that they can be a great method for authentication in web applications. Sometimes we will have some queries about which is to be used -- either local storage or cookies? Before that, I like to say that the cookies and local storage serve different purposes.

The local storage can be read on the client-side, whereas the cookies are being read on the server-side. The biggest difference is the data size is about to store, the local storage will give more space to store, whereas the cookie is limited by the size of to store.

As I said above the cookies are used on the server-side whereas the local storage is used on the client-side. The local storage is a way of storing the data in the client’s PC, by saving the key/ value pair in a web browser with no expiration date. We will discuss about using local storage in the next article, so coming to the point, as I said the cookies are a kind of small file that are stored on the user’s browser.

The cookie is a small table which will contain key and data values so, by using this it will be very useful to carry information from one session to another session. Once we are about to store data on the server without using cookies then it will be difficult to retrieve a particular user’s information without a login on each visit to that website.

So far we have seen about the overview of a cookie and the usage of it. Now in this article, I will explain about storing the username and password of a static user in the cookie table. So, I have created two components, namely the login component and dashboard component, and I have set a static username and password in authservice.ts file.

So, when a user logs in to the login form by providing his user’s credentials the authservice checks the input and redirects the user to the dashboard if the user’s credentials are valid. If the user’s credentials are not valid it will alert by throwing enter valid email or password. And if the dashboard page is being accessed by unauthorized usage the page will be redirected to the login page automatically.

Setting up

In order to use cookies in Angular, we need to install the Angular cookie library by using the following npm package manager.

npm install ngx-cookie-service –save

After installing the package manager, we need to import the cookie service in the inside of our modules.

I have used the ng zorro library UI for form design, and you can find more information about ng zorro from the following link. The next step is to design a login form. So, open login.component.html file and replace the following code.

<form fxFill #Login="ngForm" (ngSubmit)="onsubmit()">  
    <div nz-row>  
        <div nz-col nzMd="12" nzXs="24">  
            <hr />  
            <nz-form-item>  
                <nz-input-group>  
                    <div nz-col nzMd="11" nzXs="8">  
                        <nz-input-group nzPrefixIcon="user">  
                            <input type="text" nz-input name="Login_name" placeholder="User Name" id="userName"  
 
#userName="ngModel" [(ngModel)]="Obj.username">  
                            </nz-input-group>  
                            <div *ngIf="Login.submitted && userName.errors" style="color: red">  
                                <div *ngIf="userName.hasError('required')">  
  
Login ID is required  
  
</div>  
                            </div>  
                        </div>  
                    </nz-input-group>  
                </nz-form-item>  
                <nz-form-item>  
                    <div nz-col nzMd="11" nzXs="8">  
                        <nz-input-group nzPrefixIcon="lock">  
                            <input type="password" nz-input name="user_password" placeholder="Password"  
  
id="password" #password="ngModel" [(ngModel)]="Obj.password">  
                            </nz-input-group>  
                            <div *ngIf="Login.submitted && password.errors" style="color: red">  
                                <div *ngIf="password.hasError('required')">  
  
Password is required  
  
</div>  
                            </div>  
                        </div>  
                    </nz-form-item>  
                    <div class="button">  
                        <button nz-button nzType="primary">  
  
submit  
  
</button>  
                    </div>  
                </div>  
            </div>  
        </form>  

Now open login.component.ts file and replace the following code in it.

import {  
    Component,  
    OnInit  
} from '@angular/core';  
import {  
    FormGroup  
} from '@angular/forms';  
import {  
    AuthService,  
    User  
} from '../services/authservice.service';  
import {  
    Router,  
    ActivatedRoute  
} from '@angular/router';  
import {  
    CookieService  
} from 'ngx-cookie-service';  
@Component({  
    selector: 'nz-demo-card-simple',  
    templateUrl: './login.component.html'  
})  
export class LoginComponent implements OnInit {  
    Obj: User;  
    constructor(private srvLogin: AuthService, private router: Router, public activatedRoute: ActivatedRoute, private cookieService: CookieService) {  
        this.Obj = new User();  
    }  
    ngOnInit(): void {}  
    onsubmit(): void {  
        this.cookieService.set('username', this.Obj.username);  
        this.cookieService.set('password', this.Obj.password);  
        console.log(this.cookieService.get('username'));  
        console.log(this.cookieService.get('password'));  
        const a = this.Obj;  
        if (this.srvLogin.checkLogValues(this.Obj)) {  
            this.srvLogin.isloggedin = true;  
            console.log(this.srvLogin.isloggedin);  
            this.router.navigate(['/dashboard']);  
        }  
    }  
}  

The next point is to create an authentication service, we can create a service file by using the syntax.

ng generate service AuthService

The service name which I have given is Authservice and the service will be created and I have provided a default static username and password in service file so that the validation will be executed and redirected to another page (dashboard page) if the user’s credentials are being valid. Open Authservice service.ts file and replace the following code and import it in both service and as well in app-module.ts file.

import {  
    Injectable  
} from '@angular/core';  
import {  
    HttpClient  
} from '@angular/common/http';  
import {  
    CookieService  
} from 'ngx-cookie-service';  
@Injectable({  
    providedIn: 'root'  
})  
export class AuthService {  
    private username = 'vidya';  
    private password = '123456';  
    isloggedin = false;  
    constructor(private http: HttpClient) {}  
    checkLogValues(value: User): boolean {  
        if (this.username === value.username && this.password === value.password) {  
            console.log(this.username);  
            console.log(this.password);  
            // alert('Login valid');  
            return true;  
        } else {  
            alert('please enter valid data');  
            return false;  
        }  
    }  
}  
export class User {  
    username: string;  
    password: string;  
}  

After that create a component named as dashboard and open dashboard.component.html file and replace the following code.

<h3>Hello {{userDisplayName}} you are in Dashboard </h3>  
<div style="text-align:right">  
   <button nz-button nzType="danger" (click)="logout()">Logout</button>  
</div>  

The next step is to open dashboard.component.ts file and replace the following code inside it.

import {  
    Component,  
    OnInit  
} from '@angular/core';  
import {  
    AuthService,  
    User  
} from '../services/authservice.service';  
import {  
    Router,  
    ActivatedRoute  
} from '@angular/router';  
import {  
    CookieService  
} from 'ngx-cookie-service';  
@Component({  
    selector: 'dashboard',  
    templateUrl: './dashboard.component.html'  
})  
export class DashboardComponent implements OnInit {  
    Obj: User;  
    [x: string]: any;  
    userDisplayName = '';  
    password = '';  
    constructor(private srvLogin: AuthService, private router: Router, public activatedRoute: ActivatedRoute, private cookieService: CookieService) {  
        this.Obj = new User();  
        this.userDisplayName = this.cookieService.get('username');  
        this.password = this.cookieService.get('password');  
        this.Obj.username = this.userDisplayName;  
        this.Obj.password = this.password;  
        if (!srvLogin.checkLogValues(this.Obj)) {  
            router.navigate(['/login']);  
        }  
    }  
    ngOnInit(): void {}  
    logout(): void {  
        this.router.navigate(['/login']);  
        this.cookieService.deleteAll();  
    }  
}  

The following next step is to log in to the dashboard by providing the user’s credentials and after the valid login, we can see the user’s name in dashboard as a welcome note by using the user’s login name. So, after entering into the dashboard page open the developer’s tool in the browser and navigate -> Application and select cookies from storage. So, on that, we can see the user name and password have been stored in the cookie table.

So  far we have seen about storing the user’s details in the cookie table and now we can take an overview on clearing the cookies in the cookie table; for that use deleteall() method for clearing the cookies table if  the user is about to click-> logout button.

Conclusion

In this post, we have seen about using cookies in Angular for storing user’s credentials. I hope this article will be useful for you.