We're hiring
Products

Channels

Beams

Chatkit

DocsTutorialsSupportCareersPusher Blog
Sign InSign Up
Products

Channels

Build scalable, realtime features into your apps

Features Pricing

Beams

Send push notifications programmatically at scale

Pricing

Chatkit

Build chat into your app in hours, not days

Pricing
Developers

Docs

Read the docs to learn how to use our products

Channels Beams Chatkit

Tutorials

Explore our tutorials to build apps with Pusher products

Support

Reach out to our support team for help and advice

Status

Check on the status of any of our products

Products

Channels

Build scalable, realtime features into your apps

Features Pricing

Beams

Send push notifications programmatically at scale

Pricing

Chatkit

Build chat into your app in hours, not days

Pricing
Developers

Docs

Read the docs to learn how to use our products

Channels Beams Chatkit

Tutorials

Explore our tutorials to build apps with Pusher products

Support

Reach out to our support team for help and advice

Status

Check on the status of any of our products

Sign InSign Up

How to build a chatroom with Angular 7 using Chatkit

  • Ayooluwa Isaiah
January 29th, 2019
You will need Node 6+ installed on your machine. Some experience with Angular will be helpful.

In this tutorial, you’ll learn how to build a chatroom with Chatkit and Angular 7. I’ll demonstrate how to add users to the chatroom and interact with members of the room. In addition, you’ll see how to keep track of the number of users that are currently online, and also how to retrieve the message history for a chatroom.

Here’s how the final result will look:

Prerequisites

Before you proceed with this tutorial, make sure you have Node.js (version 6 and above) and npm installed on your machine. You can find installation instructions here. Also note that prior experience with building Angular and Node applications is required to be able to understand how the chatroom is built.

Getting started

The first thing we’ll do is create the server, then we’ll set up the Angular app and tie them together. Before we do any of that though, we’re going to sign up for Chatkit in the next section.

Sign up for Chatkit

Before you can leverage Chatkit features in your application, you need to sign up for a free account. Once your account is made, you need to create a new Chatkit instance. Hit the purple CREATE button and give your instance a name as shown below.

As soon as your Chatkit instance is created, you will be redirected to the dashboard for the instance. Locate the Credentials tab and take note of the Instance Locator and Secret Key as we’ll be using them on the server and in the application code.

Move to the Console tab and create a new user and a new room. You can follow the instructions on this page to learn how to do so. Take note of the room ID as we’ll be using it later.

Set up the server

Open the terminal on your computer and run the following commands to create a directory for this project, change into it and create a package.json file:

    mkdir chatroom
    cd chatroom
    npm init -y

Next, run the command below to install all the dependencies that we need to build the server:

    npm install express body-parser cors dotenv @pusher/chatkit-server -S

Once all the dependencies have been installed, create a new server.js file in the root of the chatroom directory and paste in the following contents:

    // server.js

    require('dotenv').config({ path: 'variables.env' });

    const express = require('express');
    const bodyParser = require('body-parser');
    const cors = require('cors');
    const Chatkit = require('@pusher/chatkit-server');

    const app = express();

    const chatkit = new Chatkit.default({
      instanceLocator: process.env.CHATKIT_INSTANCE_LOCATOR,
      key: process.env.CHATKIT_SECRET_KEY,
    });

    app.use(cors());
    app.use(bodyParser.json());
    app.use(bodyParser.urlencoded({ extended: true }));

    app.post('/users', (req, res) => {
      const { username } = req.body;

      chatkit
        .createUser({
          id: username,
          name: username,
        })
        .then(() => {
          res.sendStatus(201);
        })
        .catch(err => {
          if (err.error === 'services/chatkit/user_already_exists') {
            res.sendStatus(200);
          } else {
            res.status(err.status).json(err);
          }
        });
    });

    app.post('/authenticate', (req, res) => {
      const authData = chatkit.authenticate({
        userId: req.query.user_id,
      });
      res.status(authData.status).send(authData.body);
    });

    app.set('port', process.env.PORT || 5200);
    const server = app.listen(app.get('port'), () => {
      console.log(`Express running → PORT ${server.address().port}`);
    });

As you can see, we have two routes on the server. The /users endpoint serves to add a new user to the chatroom if the username has not already been taken, while the /authenticate endpoint is used to authenticate any new chatroom users before they can gain access.

We need to set up Chatkit to interact with the angular-chatroom instance we created earlier by adding the credentials as environmental variables. Create a new file called variables.env in the root of your folder in the root of the chatroom directory and change its contents to look like this:

    // variables.env

    PORT=5200
    CHATKIT_INSTANCE_LOCATOR=<your chatkit instance locator>
    CHATKIT_SECRET_KEY=<your chatkit secret key>

Now, you can start the server by running node server.js in the terminal. You should see a message indicating that the server is set up successfully on port 5200.

Set up the client

We need to install the CLI tool for Angular in the next step so that we can use it to bootstrap a new Angular application. Run the command below to install angular-cli globally on your machine:

    npm install -g @angular-cli

Once the above command finishes, the ng command will become available for you to use. You can use it to create and serve a new Angular app immediately. Within the chatroom folder, run the commands below. When prompted to add Angular routing, hit N, and choose CSS as the preferred stylesheet format.

    ng new client
    cd client
    ng serve

Navigate to http://localhost:4200 in your preferred browser. You will see the default page and some links to help you get started with Angular development.

Before we start developing our application, we need to install two additional dependencies in the client directory. Open another terminal window and cd into the client directory before running the command below:

    npm install axios @pusher/chatkit-client -S

Now, we can build the application frontend. First, let’s create the HTML template and styles for the application. Open up client/src/app/app.component.html and change it to look like this:

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

    <div class="App">
      <aside class="sidebar">
        <section  *ngIf="!currentUser" class="join-chat">
          <h2>Join Chat</h2>
          <form (ngSubmit)="addUser()">
            <input placeholder="Enter your username" type="text" name="username" [(ngModel)]="username" />
          </form>
        </section>
        <section class="online-members">
          <h2>Room Users</h2>
          <ul class="user-list">
            <li *ngFor="let user of users">
              <span class="presence {{ user.presence.state }}"></span>
              <span>{{ user.name }}</span>
            </li>
          </ul>
        </section>
      </aside>
      <main class="chat-window">
        <header class="chat-header">
          <h1>Chat</h1>
          <span class="participants"></span>
        </header>
        <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>{{ message.text }}</span>
            </li>
          </ul>
        </section>
        <footer class="chat-footer">
          <form (ngSubmit)='sendMessage()'>
            <input placeholder="Type a message. Hit Enter to send" type="text" name="message" [(ngModel)]="message">
          </form>
        </footer>
      </main>
    </div>

Next, paste the following styles into client/src/app/app.component.css:

    // 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: 100%;
      max-width: 960px;
      height: 500px;
      margin: 0 auto;
      display: flex;
      border: 1px solid #ccc;
      margin-top: 30px;
    }

    ul {
      list-style: none;
    }

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

    .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;
    }

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

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

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

    .chat-session {
      flex-grow: 1;
      display: flex;
      overflow: hidden;
    }

    .message-list {
      flex-grow: 1;
      overflow-y: auto;
      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%;
    }

Now we can go ahead and write the logic for the application. Locate app.module.ts and import FormsModule which exports the required providers and directives for template-driven forms and makes them available in our AppComponent:

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

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

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

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

    export class AppModule { }

Next, paste the following code to app.component.ts:

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

    import { Component } from '@angular/core';
    import Chatkit from '@pusher/chatkit-client';
    import axios from 'axios';

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

    export class AppComponent {
      title = 'Angular Chatroom';
      messages = [];
      users = [];
      currentUser: any;

      _username: string = '';
      get username(): string {
        return this._username;
      }
      set username(value: string) {
        this._username = value;
      }

      _message: string = '';
      get message(): string {
        return this._message;
      }
      set message(value: string) {
        this._message = value;
      }

      sendMessage() {
        const { message, currentUser } = this;
        currentUser.sendMessage({
          text: message,
          roomId: '<your room id>',
        });
        this.message = '';
      }

      addUser() {
        const { username } = this;
        axios.post('http://localhost:5200/users', { username })
          .then(() => {
            const tokenProvider = new Chatkit.TokenProvider({
              url: 'http://localhost:5200/authenticate'
            });

            const chatManager = new Chatkit.ChatManager({
              instanceLocator: '<your instance locator>',
              userId: username,
              tokenProvider
            });

            return chatManager
              .connect()
              .then(currentUser => {
                currentUser.subscribeToRoom({
                  roomId: '<your room id>',
                  messageLimit: 100,
                  hooks: {
                    onMessage: message => {
                      this.messages.push(message);
                    },
                    onPresenceChanged: (state, user) => {
                      this.users = currentUser.users.sort((a, b) => {
                        if (a.presence.state === 'online') return -1;

                        return 1;
                      });
                    },
                  },
                });

                this.currentUser = currentUser;
                this.users = currentUser.users;
              });
          })
            .catch(error => console.error(error))
      }
    }

The addUser() method is triggered whenever someone tries to join the chatroom. Once the connection to Chatkit is successful, you get a currentUser object that represents the current connected user. The subscribeToRoom method is then used to add the user to the chatroom, and any existing messages in the room will be displayed depending on the number you set in messageLimit. In this case, the most recent 100 messages will be shown. If you do not want any existing messages to be shown, you can set messageLimit to be 0.

In the hooks object, the onMessage event is triggered when a new message is sent to the chatroom. We simply append the new message to the messages array so that the new message is displayed in the chat window.

Similarly, the onPresenceChanged hook tells us when a user joins or leaves the chatroom so that the appropriate user interface updates can be made. In this case, we’re updating the users array so that the UI is updated and the appropriate status is shown for each user on the sidebar.

Finally, when a message is sent by submitting the form at the bottom of the chat window, we pass the message content and room id to Chatkit in the sendMessage() method and then clear the text input by setting this.message to an empty string.

Don’t forget to update <your instance locator> and <your room id> with the appropriate details from your Chatkit instance dashboard.

Test the chatroom in app

Open the app in a few different tabs and join the chatroom under different usernames. Send a few messages using each user. It should work just fine, similar to the GIF below:

Wrap up

This concludes my tutorial. You can checkout other things Chatkit can do by viewing its extensive documentation. Don't forget to grab the complete source code in this GitHub repository.

Clone the project repository
  • Chatkit

Products

  • Channels
  • Beams
  • Chatkit

© 2019 Pusher Ltd. All rights reserved.

Pusher Limited is a company registered in England and Wales (No. 07489873) whose registered office is at 160 Old Street, London, EC1V 9BW.