Build a live chat application that syncs messages in real time across all connected clients using Firebase — no backend server needed.
npm install @angular/fire firebase
ng add @angular/fire # connects to your Firebase project
// app.config.ts
import { provideFirebaseApp, initializeApp } from '@angular/fire/app';
import { provideFirestore, getFirestore } from '@angular/fire/firestore';
import { provideAuth, getAuth } from '@angular/fire/auth';
export const appConfig: ApplicationConfig = {
providers: [
provideFirebaseApp(() => initializeApp(environment.firebase)),
provideFirestore(() => getFirestore()),
provideAuth(() => getAuth()),
],
};
@Injectable({ providedIn: 'root' })
export class AuthService {
private auth = inject(Auth);
readonly user$ = authState(this.auth);
signInWithGoogle(): Observable<UserCredential> {
return from(signInWithPopup(this.auth, new GoogleAuthProvider()));
}
signOut(): Observable<void> {
return from(signOut(this.auth));
}
}
@Injectable({ providedIn: 'root' })
export class ChatService {
private firestore = inject(Firestore);
getMessages(roomId: string): Observable<Message[]> {
const messagesRef = collection(this.firestore, `rooms/${roomId}/messages`);
const q = query(messagesRef, orderBy('createdAt', 'asc'), limitToLast(50));
return collectionData(q, { idField: 'id' }) as Observable<Message[]>;
}
sendMessage(roomId: string, text: string, user: User): Promise<void> {
const messagesRef = collection(this.firestore, `rooms/${roomId}/messages`);
return addDoc(messagesRef, {
text,
uid: user.uid,
photoURL: user.photoURL,
displayName: user.displayName,
createdAt: serverTimestamp(),
}).then(() => void 0);
}
}
@Component({
standalone: true,
imports: [AsyncPipe, FormsModule],
template: `
<div class="messages">
@for (msg of messages$ | async; track msg.id) {
<div [class.own]="msg.uid === currentUser?.uid">
<img [src]="msg.photoURL" />
<p>{{ msg.text }}</p>
</div>
}
</div>
<form (ngSubmit)="send()">
<input [(ngModel)]="newMessage" name="msg" placeholder="Type a message..." />
<button type="submit">Send</button>
</form>
`,
})
export class ChatRoomComponent {
private chat = inject(ChatService);
private auth = inject(AuthService);
roomId = input.required<string>();
messages$ = this.chat.getMessages(this.roomId());
currentUser = inject(Auth).currentUser;
newMessage = '';
send(): void {
if (!this.newMessage.trim() || !this.currentUser) return;
this.chat.sendMessage(this.roomId(), this.newMessage, this.currentUser);
this.newMessage = '';
}
}
All Comments