Tutorial: Building a Real-Time Chat App with Angular and Firebase

July 10, 2021


Introduction

Real-time applications are everywhere today — from chat apps and collaborative tools to live notifications. Angular, combined with Firebase’s powerful backend-as-a-service (BaaS), makes building these apps fast and scalable.

In this tutorial, we’ll build a real-time chat application using:

  • Angular (with RxJS Observables)
  • AngularFire (the official Angular library for Firebase)
  • Firebase Authentication for user login
  • Cloud Firestore for storing messages
  • Angular Material for sleek UI components

By the end, you’ll have a fully functional chat app with real-time message updates, user authentication, and a polished UI.


Prerequisites

  • Basic Angular knowledge
  • Node.js and Angular CLI installed
  • Firebase project created in the Firebase Console
  • Angular Material setup (we’ll cover this)

Step 1: Set Up Angular and Firebase

Create a new Angular app if you don’t have one:

ng new angular-chat-app --routing --style=scss
cd angular-chat-app

Install AngularFire and Firebase SDK:

npm install firebase @angular/fire

Step 2: Configure Firebase Project

In your Firebase Console:

  1. Create a new project (or use existing)
  2. Enable Authentication → Sign-in methods → Email/Password (or Google, etc.)
  3. Enable Cloud Firestore in test mode for now (secure rules later)

Get your Firebase config (found in project settings):

// src/environments/environment.ts
export const environment = {
  production: false,
  firebaseConfig: {
    apiKey: 'YOUR_API_KEY',
    authDomain: 'your-app.firebaseapp.com',
    projectId: 'your-app',
    storageBucket: 'your-app.appspot.com',
    messagingSenderId: '...',
    appId: '...'
  }
};

Step 3: Initialize Firebase in Angular

In your AppModule, import AngularFire modules:

import { AngularFireModule } from '@angular/fire/compat';
import { AngularFireAuthModule } from '@angular/fire/compat/auth';
import { AngularFirestoreModule } from '@angular/fire/compat/firestore';
import { environment } from '../environments/environment';

@NgModule({
  declarations: [...],
  imports: [
    BrowserModule,
    AngularFireModule.initializeApp(environment.firebaseConfig),
    AngularFireAuthModule,
    AngularFirestoreModule,
    // Other imports ...
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }

Step 4: Implement Authentication Service

Create a simple auth service for login/logout:

import { Injectable } from '@angular/core';
import { AngularFireAuth } from '@angular/fire/compat/auth';
import firebase from 'firebase/compat/app';

@Injectable({ providedIn: 'root' })
export class AuthService {
  user$ = this.afAuth.authState;

  constructor(private afAuth: AngularFireAuth) {}

  async login(email: string, password: string) {
    return await this.afAuth.signInWithEmailAndPassword(email, password);
  }

  async logout() {
    await this.afAuth.signOut();
  }

  async register(email: string, password: string) {
    return await this.afAuth.createUserWithEmailAndPassword(email, password);
  }
}

Step 5: Building the Chat Component

Create a chat component that displays messages and sends new ones:

ng generate component chat

Firestore Message Model

export interface ChatMessage {
  id?: string;
  text: string;
  userId: string;
  userName: string;
  timestamp: firebase.firestore.FieldValue;
}

Chat Service to Manage Messages

import { Injectable } from '@angular/core';
import { AngularFirestore, AngularFirestoreCollection } from '@angular/fire/compat/firestore';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';

@Injectable({ providedIn: 'root' })
export class ChatService {
  private messagesCollection: AngularFirestoreCollection<ChatMessage>;
  messages$: Observable<ChatMessage[]>;

  constructor(private afs: AngularFirestore) {
    this.messagesCollection = afs.collection<ChatMessage>('messages', ref => ref.orderBy('timestamp', 'asc'));
    this.messages$ = this.messagesCollection.valueChanges({ idField: 'id' });
  }

  sendMessage(message: ChatMessage) {
    return this.messagesCollection.add(message);
  }
}

Chat Component Template (chat.component.html)

<div class="chat-container">
  <div class="messages">
    <div *ngFor="let msg of messages$ | async" class="message">
      <strong>{{ msg.userName }}:</strong> {{ msg.text }}
    </div>
  </div>

  <form (ngSubmit)="sendMessage()" #chatForm="ngForm">
    <mat-form-field class="full-width">
      <input matInput placeholder="Type a message" [(ngModel)]="newMessage" name="message" required />
    </mat-form-field>
    <button mat-raised-button color="primary" type="submit" [disabled]="chatForm.invalid">Send</button>
  </form>
</div>

Chat Component Logic (chat.component.ts)

import { Component } from '@angular/core';
import { ChatService } from '../services/chat.service';
import { AuthService } from '../services/auth.service';
import firebase from 'firebase/compat/app';

@Component({
  selector: 'app-chat',
  templateUrl: './chat.component.html',
  styleUrls: ['./chat.component.scss']
})
export class ChatComponent {
  messages$ = this.chatService.messages$;
  newMessage: string = '';
  currentUser: any;

  constructor(private chatService: ChatService, private authService: AuthService) {
    this.authService.user$.subscribe(user => {
      this.currentUser = user;
    });
  }

  async sendMessage() {
    if (!this.newMessage.trim()) return;

    const message = {
      text: this.newMessage,
      userId: this.currentUser.uid,
      userName: this.currentUser.email,
      timestamp: firebase.firestore.FieldValue.serverTimestamp()
    };

    await this.chatService.sendMessage(message);
    this.newMessage = '';
  }
}

Step 6: Adding Angular Material UI

Install Angular Material:

ng add @angular/material

Import Material modules in your AppModule:

import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input';
import { MatButtonModule } from '@angular/material/button';

@NgModule({
  imports: [
    MatFormFieldModule,
    MatInputModule,
    MatButtonModule,
    // ...
  ],
})
export class AppModule { }

Step 7: User Authentication UI

Create simple login and registration components to handle user auth (omitted here for brevity). Bind these to AuthService methods.


Final Thoughts and Next Steps

Congratulations! You now have a real-time chat app powered by Angular and Firebase.

What you can add next:

  • User presence indicators
  • Message read receipts
  • Typing indicators
  • Push notifications

Firebase and AngularFire handle scalability and real-time updates, making this a solid foundation.

Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply

Your email address will not be published. Required fields are marked *