Canonical URL: Republished from munonye.com. Full code on GitHub.
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
- RAG with Spring Boot (M8-A)
- [Angular signals deep dive (M10-B)](https://www.munonye.com/angular-signals-ai-chat-state-management
Read the full tutorial with all code on munonye.com →
Full tutorial: Build a Streaming Chat UI in Angular 19 (2026)
Top comments (0)