This article is to explain how to build a real time application very rapidly using AWS Amplify with Angular.

What is AWS Amplify?

From their website:

AWS Amplify is a set of tools and services that enables mobile and front-end web developers to build secure, scalable full stack applications, powered by AWS.

Prerequisites:

  • Node.js version 10 or later
  • AWS Account
  • Angular CLI version 10 or later
  • Basic understanding of Angular concepts

Create the skeleton of the chat application using Angular CLI

npx ng new amplify-chat-angular

Setting up the project

For this tutorial, we’ll be using AWS Amplify to power our API, real-time messaging, authentication in our Angular app.

npm install --save aws-amplify

Then run the following, to initialize our Angular app as an Amplify project.

amplify init

You will be prompted to answer a few questions about your project.

Enter a name for the project (amplifychatangular)
# For this tutorial, we'll only use the dev environment
Enter a name for the environment (dev)
# Here, just choose the editor you want to associate with Amplify
Choose your default editor
# Since we're building a Angular app, choose JavaScript and React
Choose the type of app that you're building (javascript)
What JavaScript framework are you using (angular)
# Choose the default options for these
Source directory path (src)
Distribution directory path (build)
Build command (npm run build)
Start command (npm run start)
# Remember the profile you created when you configured AWS Amplify?
# Let's choose that profile in this step
Do you want to use an AWS profile

After answering all these questions, Amplify should have auto generated an aws-export.js file which later is used to save all the amplify config.

Now all that’s left is to configure our Angular app to use AWS Amplify.

Open src/main.ts and add the following lines after the last import statement.

import Amplify from '@aws-amplify/core';
import awsExports from './aws-exports';


Amplify.configure(awsExports);

And that’s it. You’ve successfully configured an Angular app to use AWS Amplify.

Setting up the GraphQL API and model

The next step would be adding the API and our model. For this tutorial, we’ll be using a GraphQL API so run the following to add an AppSync GraphQL API to our app.

amplify add api

When prompted, choose the default options and the CLI should open a GraphQL schema that would look like this.

File: amplify/backend/api/amplifychatangular/schema.graphql

type Todo @model {
  id: ID!
  name: String!
  description: String
}

Since we’re building a chat app, a Todo model doesn’t really work for us. So let’s change that.

type Message
  @model
  @key(name: "byChannelID", fields: ["channelID", "createdAt"], queryField: "messagesByChannelID") {
  id: ID!
  channelID: ID!
  author: String!
  body: String!
  createdAt: AWSDateTime
  updatedAt: AWSDateTime
}

Here, we are creating a Message model with the fields idauthor (which is the name of the author), bodycreatedAt, and updatedAt.

Explanation:

@key(name: “byChannelID”, fields: [“channelID”, “createdAt”], queryField: “messagesByChannelID”




AWSDateTime



ID
author
body

We created a new index for the Messages table. We have added @key which is an AWS Amplify GraphQL directive, like @model. This basically tells AppSync to create a secondary key with the name of byChannelID. The fields array comprises our new key. The first field here will always be the hash key and the second one, our sort key. Lastly, the queryField parameter tells AppSync to create a new query operation using this newly created key with the value of queryField as the name.
AWSDateTime is a scalar type provided by AWS AppSync. It’s basically a string in the form of YYYY-MM-DDThh:mm:ss.sssZ. You can read more about AppSync scalar types here. This will be automatically set by AppSync on mutations.
Unique Id of the message
Name of the author
Message Content

Save, exit, then run the following command to provision the API in the cloud. Again, choose the default options for the prompts.

amplify push

This might take a while so grab a cup of coffee.

Once this finishes, congratulations! Your API is now live. You can now start making GraphQL queries and mutations on it. It’s so easy it’s like cheating right?

When you ran amplify push, you saw a bunch of things happening. These logs are AWS CloudFormation commands being executed to provision your app in AWS including setting up AppSync, DynamoDB, attaching IAM roles, and a few other things – things that you normally wouldn’t want to touch as a mobile or front-end developer. The Amplify CLI tool abstracted those away into one simple command.

GraphQL Mutation, Query & Resolver Generator

Amplify should have automatically generated angular specific, Mutation & Query automatically relevant to the model that we have created.

Check src/app/API.service.ts for the reference, using API service, we will be able to do, createMessage, updateMessage, listMessages, deleteMessages and etc.

It also generates real-time graphql subscriptions, for which we don’t have to make any web socket connections explicitly, all will be managed by Amplify.

Setting up the UI

Before we get to the good part, we’ll be setting up our UI: a list of messages and a chat bar — nothing too fancy!

So to do that, open src/app.component.html and add the below given code.

<div id="root">
  <div class="container">
    <div class="messages">
      <div class="messages-scroller">
        <ng-container *ngFor="let message of messages">
          <div [ngClass]="message.author === username ? 'message me' : 'message'">
            {{message.body}}
          </div>
        </ng-container>
      </div>

    </div>
    <div class="chat-bar">
      <div class="form">
        <input #messageInput type="text" name="messageBody" placeholder="Type your message here" value=""
          (keyup.enter)="send($event, messageInput)" />
      </div>
    </div>
  </div>
</div>

Then open style.scss and replace the contents with the following code so we’ll have a nice look to our view.

/* You can add global styles to this file, and also import other style files */
* {
  box-sizing: border-box;
  font-family: 'Roboto', sans-serif;
}

html, body {
  height: 100%;
  margin: 0;
}

#root {
  display: flex;
  align-items: center;
  justify-content: center;
  background: #f8f8f8;
  height: 100%;
}

.container {
  display: flex;
  flex-direction: column;
  width: 540px;
  height: 680px;
  background: white;
  border-radius: 16px;
  box-shadow: 0 2px 16px rgba(0, 0, 0, 0.0);
}

.messages {
  flex: 1;
  position: relative;
}

.messages-scroller {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  display: flex;
  flex-direction: column;
  padding: 16px;
  overflow-y: scroll;
}

.message {
  align-self: flex-start;
  margin-top: 4px;
  padding: 8px 12px;
  max-width: 240px;
  background: #f1f0f0;
  border-radius: 16px;
  font-size: 14px;
}

.message.me {
  align-self: flex-end;
  background: #2196F3;
  color: white;
  width: fit-content;
//   margin: 10px;
}

.chat-bar {
  height: 64px;
  border-top: 1px solid #ddd;
}

.chat-bar .form {
  height: 100%;
  padding: 16px;
}

.chat-bar .form input {
  width: 100%;
  height: 32px;
  padding: 8px 16px;
  border: 1px solid #ddd;
  border-radius: 16px;
  outline: none;
}

.chat-bar .form input:focus {
  border: 1px solid #2196F3;
}

/* width */
::-webkit-scrollbar {
  width: 10px;
}

/* Track */
::-webkit-scrollbar-track {
  background: #f1f1f1; 
}
 
/* Handle */
::-webkit-scrollbar-thumb {
  background: #888; 
}

/* Handle on hover */
::-webkit-scrollbar-thumb:hover {
  background: #555; 
}

It doesn’t do much for now so let’s load the messages we created in the previous article and hook up the event handlers.

Loading / Sending messages real time

We’ll want to load messages when our app component gets loaded, and to do that we’ll use APIService, and the Amplify API library.

Open up src/app.component.ts and import the APIService and Router and inject them in constructor.

  constructor(
    private api: APIService,
    private router: Router
  ) { }

Now we need create event handlers

listMessages => to Load the previously sent / received messages

send => To send the message

onCreateMessage => Listen to real time message add event

  1. listMessages: Here we are fetching the massages by channel Id using MessagesByChannelId(graphql query), user can use dynamic channel ID.
  listMessages(): void {
    this.api.MessagesByChannelId('1').then((val) => {
      console.log(val);
      this.messages = val.items;
    });
  }

2. send: We will use this method to send the message written by the user to a specific channel using CreateMessage graphql Mutation.

  send(event, inputElement: HTMLInputElement): void {
    event.preventDefault();
    event.stopPropagation();
    const input = {
      channelID: '1',
      author: this.username.trim(),
      body: inputElement.value.trim()
    };
    this.api.CreateMessage(input).then((val) => {
      console.log('Send Message Success =>', val);
      inputElement.value = '';
    });
  }

3. onCreateMessage: We will use graphql subscription to listen realtime message create event. Whenever anyone adds any message to channel “1”, This event will be triggered.

  onCreateMessage(): void {
    this.api.OnCreateMessageListener.subscribe(
      {
        next: (val: any) => {
          console.log(val);
          this.messages.push(val.value.data.onCreateMessage);
        }
      }
    );
  }

Full Code for app.component.ts file can be found here.

Full Code for the whole app implementation can be found here

Working Demo

Unimedia Technology

Here at Unimedia Technology we have a team of Angular Developers that can develop your most challenging Web Dashboards and Web apps using the latest AWS technologies.

RSS
Follow by Email
LinkedIn
Share