To follow this post, some basic knowledge of Angular is required. Since we’re using Angular we’re gonna also see some TypeScript code. Some basic knowledge here would also help. One would need Node 10 or any newer version installed, in order to play with the sample code from GitHub. That’s all, having this, following this tutorial should be straight forward.

We’ll go from scratch. How to generate a new Angular application. How to create a new account (free) on CometChat Pro and how to create an anonymous group chat and post messages in it.

We’ll not focus on the UI that much, more on the functional part, but here’s how it will look in the end:

Login-screen-for-our-demo-app

Group-screen-for-our-demo-app

The code is on GitHub here, in case you want to dive right in. Clone the repo and have fun, don’t forget to get back to the article to follow the tutorial 😉

New project

The first thing we have to do is create a new project so we can work on our awesome application. For this we need the Angular CLI, installed globally:

npm install -g @angular/cli

And then we can create the project:

ng new AngularChat

Or we can use npx, the node package runner. We achieve the same result, without having to install anything globally:

npx @angular/cli new AngularChat

Follow the interactive installation. Say yes to routing and pick CSS when asked what stylesheet format you want to use.

This will generate all the structure and code required for a new Angular application. It will also install all the dependencies. Once the command has finished running, you can open the new folder in your preferred editor(I love VsCode). You can start the local development server by running npm start or ng serve. The two commands do the same thing. Now you can go to http://localhost:4200 and see the application up and running.

CometChat Pro account

The second important thing that we need to do, is to create a free CometChat Pro account.

You can go to the website and click on the big red button that says “Get started for free”. Once you fill in all the required information you’ll have a trial account setup and ready to go.

On the CometChat dashboard, you’ll see an overview of your account. In the ‘Add new app’ dialog, enter a name and click the plus sign to create a new application.

Hold your horses ⚠️🐴!
To follow this tutorial or run the example source code you'll need to create a V1 application.

v2 will be out of beta soon at which point we will update this tutorial.

Take note of the Application ID as we’ll use it to communicate with the ComeChat API.

From the left side menu, go to API Keys, since we’ll have to create a new one for our application. Give it whatever name suits you, and select Auth Only as scope. Take a note of this API Key since we’ll use it in the application.

The CometChat app comes with five users and a group already created, so we have everything we need. The existing users are: superhero1, superhero2, superhero3, superhero4 and naturally, superhero5. One group that would fit all these five is supergroup. You can see them all using the CometChat dashboard.

CometChat SDK

With all this in place, we now add the CometChat package to our application. This will help us work more easily with the API. Instead of us having to make all the calls we can use pre-made functions for the operations that we want to make.

To add the package run:

npm install @cometchat-pro/chat

Now we can reference the library in our project, and use whatever functions we need from there in our code:

import { CometChat } from '@cometchat-pro/chat';

TypeScript type definitions

At the time of this writing, the library does not have TypeScript type definitions. Though this is something that might come 😉 .

All Angular/TypeScript developers love type definitions. To make it easier to follow the tutorial and play with the code, I’ve created a few, for the functions that we’re going to use.

This was done by creating a new *.d.ts file inside the src folder of our app. The TypeScript compiler will pick it up and show us the type definitions when working with the code. This is not something you need to do, but if curious you can have a look at the file on GitHub.

Application structure

Now let’s think about our application a bit, we want an anonymous chat, so this will be a component. But before we get to this component we also want to allow the user to login to our application. So we’ll need another component for that. Also it’s a best practice to wrap the usage of a library inside a service, so we’ll need a CometChat service class also.

With this in mind, we’ll use the Angular CLI to generate these components for us. If you installed the CLI globally at the beginning you can use the ng command. If not, you can use the locally installed one by running npm run ng.

Now to generate our components:

ng generate component components/Login
ng generate component components/GroupView

We pass the generate argument first, to tell the CLI what we want to do. Then we specify the blueprint of what we want to generate, in this case a component. Then we specify the name of the component. In our case I’ve also added components/ before the actual name so that all the components are in the same folder.

To create the service class:

ng generate service services/CometChat

Same thing as before. We changed the blueprint to service this time and specified a services folder for this class to be in.

Now we have the structure of our application in place.

Routing

We have our two components in place, now we have to tell Angular when to load them.

In our App routing module (app-routing.module.ts) we can update the routes like this:

const routes: Routes = [
  { path: '', redirectTo: 'login', pathMatch: 'full' },
  { path: 'login', component: LoginComponent },
  { path: 'chat', component: GroupViewComponent },
];

The first one is a redirect when our application starts we want to go to the login path. The second one tells Angular that whenever we go to login we want to show the LoginComponent. The second one does the same but with the chat path and the GroupViewComponent.

We can now go on and implement some functionality in our application.

Initialising CometChat

The first thing we need to do to use the CometChat SDK is to initialise it. This has to be done before calling any other methods. Due to this, a good place to implement it would be when our application initializes. Meaning the ngOnInit hook of the app component.

In our CometChat service, we create an init method. It will have only one parameter, the application ID. Inside, we’ll call the init method of the CometChat library:

init(apiKey: string) {
  CometChat.init(apiKey).then(
    msg => console.log('Initialized succesfull: ', msg),
    err => console.log('Initialization failed: ', err),
  );
}

The init method will return a Promise. While it’s not mandatory, it’s a good practice to handle the result using a then call. Printing some messages in case of success or failure is enough for us to make it easier to debug the code.

In our app component we have to add the service as a parameter to the constructor:

constructor(private cometChat: CometChatService) {}

You can notice that before the name there is the private access modifier. This is a nice little trick in TypeScript that allows us to create a field with this name on the class.

We can move on and initialise CometChat when our application starts, so in the same app component:

ngOnInit() {
  this.cometChat.init('CometChatApp ID');
}

Global config values

It’s a good practice to keep global values in the same file. A good place to do this is the angular environment config files(environment.ts). We already have an object called environment there. We can add a property on it with the values for the CometChat application id and API key:

export const environment = {
  production: false,
  cometChat: {
    apiKey: 'API_KEY_HERE',
    appId: 'APP_ID_HERE',
  }
}

This will allow us to reference them through the application whenever needed. So in the example above, instead of hardcoding the value we can do:

this.cometChat.init(environment.cometChat.appId);

Login component

Everything is initialized. Now we can move on and allow the user to authenticate to our application.

For this we are gonna use the login function from CometChat. This allows a user to be authenticated based on a user id and API key. Even though this is an anonymous chat app, we need to authenticate to the CometChat API so that we can read and write information related to our application.

Inside our CometChat service, we create a new login method and perform the call:

login(userId: string) {
  return CometChat.login(userId, environment.cometChat.apiKey)
  .then(
    user => console.log('Login succesfull: ', user),
    err => console.log('Login failed: ', err),
  );
}

We pass in the user id and use the API key from the environment object. And as we did before, we handle the outcome Promise result by writing some values in the console. This method also returns the result of the API call. We handle it here, but we also want to know where we use it if it’s successful or not.

When successful, the result of this method call will be the logged in user. It might be useful to hold onto it. So let's create a local user property and assign it when we have a response.

user => {
  console.log('Login succesfull: ', user);
  this.currentUser = user;
}

With this in place we can move on and add an input where the user can enter a name and a submit button. In our login component html template we’ll have this code:

<label for="userName">Username</label>
<input id="userName" type="text" #userName/>
<button>Join chat</button>

When the user clicks the ‘Join chat’ button, we will take the text value from the input and call the login method in our class. As we did in the application component. We have to use dependency injection to get an instance of the CometChat service:

constructor(private cometChat: CometChatService, private router: Router) {}

We also have the Angular Router there since we’ll use it to navigate to the group chat page.

Inside the login method, we’ll call the CometChat service. If the login is successful, we redirect the user to the chat page:

login(userId: string) {
  this.cometChat
    .login(userId)
    .then(() => this.router.navigateByUrl('chat'))
}

If everything goes ok, once a user enters a valid name and hits join they can get to our group view component.

Group view component

This is our most complex component and where most of the action will take place. We’ll be able to see messages here and write new ones.

To make things easier we’ll start with the template. We need a list, to show all the messages and an input with a button, to allow users to write new messages. For the list of messages we can have something like this:

<div class="messages">
  <p>
    <i>{{ message.sender.uid }}</i> <br />
    {{ message.text }}
  </p>
</div>

We iterate over messages collection using the ngForOf directive from Angular. For each message, we show the sender uid. This means the name of the user that wrote the message, and the text of the message.

We also use the ngClass directive to add a css class only to messages that were written by the logged in user. This is something we’re used to from most chat apps. Usually, they have a different color or placed in a different position on the screen.

For this to work we need to have the properties defined in our class:

messages = [];

get currentUser() {
  return this.chatService.currentUser;
}

Here we can see where we’re actually using the currentUser that we’ve stored when the login is performed.

As before, the CometChat service is added in the constructor as a parameter:

constructor(private chatService: CometChatService) {}

Good, now we also have to show some messages 🙂. There are two parts to this, we need to fetch existing messages, that were written before. And after that, we need to register a listener for any new message that might arrive.

Previous messages

To fetch messages, we need to build something like a query and specify what we want to retrieve. The SDK has the MessagesRequestBuilder class that allows us to do exactly this.

We have different methods on it, in a fluent-like API, that allows us to set different properties for our request:

  • number of messages to retrieve
  • user or group id
  • filtering methods like timestamp or message id

In our case we want to fetch messages from a group, so we need to specify only the group id. Ok, maybe a limit would also be a sensible thing to add 😃. After we’ve set all the properties we want we can call the build method. This will create the query and give us back an instance of MessageRequest that we can use to fetch messages:

getPreviousMessages(groupId: string) {
  const messageRequest = new CometChat.MessagesRequestBuilder()
    .setGUID(groupId)
    .setLimit(100)
    .build();
    return messageRequest.fetchPrevious();
}

The message request class has two methods: fetchNext and fetchPrevious. As the name suggests, next will get messages after the filters, similar to greater than. Previous will get the messages before, or lower than.

In our case, we did not set any filter so any of the two should work. The method above was added to the CometChat service class. We can call it in our group view component to fetch the previous messages:

this.chatService
  .getPreviousMessages('supergroup')
  .then(messages => (this.messages = messages))

When we get the response back, we assign the messages to the local property. Angular will notice there is something new and will render our component with the new values.

Message listener

We already have messages that were previously written, but we also want to show incoming, real-time, messages. Messages that other users might write as we look at the screen. To get them we need to register a message listener. For this we need a unique listener ID. Something related to the screen or part of the application the chat is linked to. We can then use the MessageListener class to register handlers for different type of messages:

listenForMessages(listenerId: string, onMessageReceived: (msg: any) => void) {
  CometChat.addMessageListener(
    listenerId,
    new CometChat.MessageListener({
      onTextMessageReceived: onMessageReceived,
    })
  );
}

For now, we only care about text messages. That’s the only listener we’ve registered. But it also has properties like onMediaMessageReceived and onCustomMessageReceived for other types.

Having added the above method to the CometChat service class, we can use it in our group view component. After we’ve read all the previous messages, we can listen for new ones:

this.chatService.listenForMessages(this.listenerId, msg => this.messages.push(msg));

We have a local property listnerId. With a value of ‘Web_App_Listener_Group_ID’, but you can use pretty much any value you want. This should be an unique value for our application, but since we have only one listener, we’re safe. As a method, we pass a function that will take any new message and add it to our messages array. Again, this will trigger the component to be rendered and we’ll see new messages on the screen.

It’s a good practice to remove message listeners when they are no longer needed. So let’s do that.

In our CometChat service we add the remove method:

removeListener(listenerId: string) {
  CometChat.removeMessageListener(listenerId);
}

And in our group view component, we add a handler for the destroy event and call it there:

ngOnDestroy(): void {
  this.chatService.removeListener(this.listenerId);
}

Adding new messages

The last part we need to do is write new messages and send them to the server.

First, we need to update the template with an input and button for this:

<div class="messageInput">
  <input type="text" placeholder="enter a text message" #messageText />
  <button (click)="sendMessage(messageText.value); messageText.value = ''">
    Send
  </button>
</div>

When the user clicks the ‘Send’ button, we take the text from the input and call the sendMessage method on our class. As a bonus we also clear the input value, to allow the user to write a new message.

To send the message we have to use the, you guessed it, sendMessage function. Before we send the message we have to create it:

const message = new CometChat.TextMessage(
  receiverId,
  text,
  CometChat.MESSAGE_TYPE.TEXT,
  CometChat.RECEIVER_TYPE.GROUP
);

This is an example of how to send text messages. The first value, receiverId, is the user or group id of whom we want to send the message to. Second, and the easiest one, is the text content of the message.

The third one is the type of the message, in our case, text. It can also be file, image, video or audio.

The last value represents the type of receiver, either a user or a group. In our case a group.

Once we have the message created, we send it to the server:

CometChat.sendMessage(message);

This was the sendMessage function, implemented inside the CometChat service class. You can have a look at the code here.

With this function in place we can go to our group view component and implement the sendMessage function there:

sendMessage(message: string) {
  this.chatService.sendMessage('supergroup', message);
}

One thing to keep in mind. The messages the user is sending will not get back into the message listener that we’ve registered. To see them on the screen after they are sent we have to manually add them to the messages array:

this.messages.push({
  text: message,
  sender: { uid: this.currentUser.uid }
});

That was it! Now we can receive and send messages in our super group 🙂.

Conclusion

This was a way to create a generic anonymous chat application with Angular and CometChat. You’ve went through the basics of using CometChat in an Angular context. Now can build on this and extend your application with new and cool capabilities.

Group screen with messages

The sample code on GitHub contains a bit more error handling and some basic css to make everything a bit more tidy. Don’t hesitate to check it out 😉.

Follow this blog for more tutorials and tips on how to use CometChat.