July 1, 2026

Build a Streaming Chat UI in Angular 19 (2026)

Updated — July 1, 2026 · Angular 19 chat UI for the Spring AI backend from M7-A.

Kindson Munonye · Software engineer & technical author
GitHub · LinkedIn · About · YouTube
Last updated by Kindson Munonye — July 1, 2026


📚 Tutorial hubs:
AI Developer Tutorials ·
Spring Boot ·
Angular ·
CRUD + REST guide

Source code: munonye-ai-chat-spring-angular on GitHub

Estimated reading time: 12–15 minutes · Last updated: July 1, 2026


This Angular OpenAI chat tutorial builds a chat UI on Angular 19 that talks to the Spring AI backend from M7-A. Part of the AI Developer Tutorials hub.

Prerequisites: M7-A backend running on port 8080, Node 18+, Angular CLI 19.
Time: ~50 minutes.

Step 1 — Create the Angular app

ng new chat-ui --routing --style=scss --ssr=false
cd chat-ui
ng serve --port 4200

Configure HttpClient in main.ts:

import { bootstrapApplication } from '@angular/platform-browser';
import { provideHttpClient } from '@angular/common/http';
import { AppComponent } from './app/app.component';

bootstrapApplication(AppComponent, {
  providers: [provideHttpClient()],
});

Step 2 — Chat service

// chat.service.ts
import { Injectable, inject } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';

export interface ChatMessage {
  role: 'user' | 'assistant';
  content: string;
}

@Injectable({ providedIn: 'root' })
export class ChatService {
  private http = inject(HttpClient);
  private apiUrl = 'http://localhost:8080/api/chat';

  send(message: string): Observable<{ reply: string }> {
    return this.http.post<{ reply: string }>(this.apiUrl, { message });
  }
}

Step 3 — Chat component (standalone)

import { Component, inject, signal } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { ChatService, ChatMessage } from './chat.service';

@Component({
  selector: 'app-chat',
  standalone: true,
  imports: [FormsModule],
  template: `
    <div class="chat">
      @for (msg of messages(); track $index) {
        <div [class]="msg.role">{{ msg.content }}</div>
      }
      @if (loading()) { <p>Thinking…</p> }
      <form (ngSubmit)="send()">
        <input [(ngModel)]="input" name="input" [disabled]="loading()" />
        <button type="submit" [disabled]="loading() || !input.trim()">Send</button>
      </form>
    </div>
  `,
  styles: [`
    .user { text-align: right; color: #1565c0; margin: 8px 0; }
    .assistant { text-align: left; color: #2e7d32; margin: 8px 0; }
  `],
})
export class ChatComponent {
  private chat = inject(ChatService);
  messages = signal<ChatMessage[]>([]);
  loading = signal(false);
  input = '';

  send(): void {
    const text = this.input.trim();
    if (!text) return;
    this.messages.update(m => [...m, { role: 'user', content: text }]);
    this.input = '';
    this.loading.set(true);
    this.chat.send(text).subscribe({
      next: res => {
        this.messages.update(m => [...m, { role: 'assistant', content: res.reply }]);
        this.loading.set(false);
      },
      error: () => {
        this.messages.update(m => [...m, { role: 'assistant', content: 'Error contacting AI service.' }]);
        this.loading.set(false);
      },
    });
  }
}

Wire ChatComponent in AppComponent imports.

Step 4 — Connect to reactive forms hub

For production forms validation patterns, cross-link Angular reactive forms validation guide.

Next steps

Related:
AI Developer Tutorials hub ·
Angular CRUD Part 1 ·
Spring AI overview

Kindson Munonye

Kindson Munonye is a software engineer and technical author specializing in Angular, Spring Boot, and microservices architecture. He publishes step-by-step tutorials with source code covering CRUD operations, reactive forms, CQRS, event sourcing, and REST API integration.GitHub · LinkedIn · About · YouTube

View all posts by Kindson Munonye →
0 0 votes
Article Rating
Subscribe
Notify of
guest
0 Comments
Oldest
Newest Most Voted