Claude Code untuk Angular: CLI, Standalone, Forms, HTTP, dan Testing
Workflow Claude Code untuk Angular CLI, standalone component, Reactive Forms, HttpClient, unit test, E2E, dan review.
Claude Code paling berguna di proyek Angular saat dipakai sebagai partner yang membaca repository, bukan sekadar generator component. Perubahan Angular yang realistis biasanya menyentuh Angular CLI, standalone component, Reactive Forms, service bertipe dengan HttpClient, unit test, E2E, dan review akhir.
Standalone component adalah component yang mendeklarasikan dependency sendiri lewat imports, tanpa harus didaftarkan di NgModule. Reactive Forms adalah cara mengelola nilai form dan aturan validasi secara eksplisit di TypeScript. HttpClient adalah API resmi Angular untuk komunikasi dengan backend. Kalau istilah ini tidak muncul di prompt, Claude Code bisa menghasilkan kode yang terlihat benar tetapi tidak cocok dengan pola project.
Gunakan referensi resmi saat bekerja: Angular CLI, Reactive forms, HttpClient, Angular testing, dan Claude Code workflows. Untuk konteks tambahan, baca Tips TypeScript, Strategi Testing, dan praktik CLAUDE.md.
Tentukan batas kerja
Jangan mulai dengan “buatkan form”. Minta Claude Code membaca project dulu. Harness berarti batas kerja aman untuk agent: file yang boleh disentuh, aturan yang harus dijaga, command verifikasi, dan risiko yang harus dicari.
Baca project Angular ini sebelum mengedit. Periksa package.json, angular.json, dan src/app.
Jelaskan apakah project memakai standalone components, test runner apa yang dipakai,
di mana HttpClient di-provide, dan konvensi penamaan apa yang terlihat.
Jangan edit file dulu.
| Area | Tugas Claude Code | Keputusan manusia |
|---|---|---|
| Angular CLI | command generate, path, dependency check | ownership route, naming |
| Component | imports, template, signals, event | copy UI, accessibility |
| Reactive Forms | FormGroup, validators, submit state | aturan bisnis |
| Service / HTTP | tipe, method API, test backend | kontrak API, auth |
| Testing | unit, E2E, regression | target coverage |
flowchart LR
P[Prompt] --> C[Angular CLI]
C --> A[Standalone component]
A --> F[Reactive Forms]
A --> S[Ticket service]
S --> H[HttpClient]
F --> U[Unit tests]
A --> E[E2E tests]
U --> R[Review]
E --> R
Buat baseline dengan Angular CLI
Untuk eksperimen baru, Angular CLI memberi struktur bersih. Untuk repository lama, minta Claude Code membaca konfigurasi dulu.
npm install -g @angular/cli
ng new support-desk-angular --standalone --routing --style css
cd support-desk-angular
ng generate component features/tickets/ticket-intake --standalone
ng generate service data/ticket
ng test
Menjalankan ng test sebelum edit penting agar failure lama tidak tercampur dengan regression baru. Jika ada beberapa orang mengerjakan slug atau feature lain, tulis juga bahwa Claude Code hanya boleh menyentuh area yang ditugaskan dan tidak boleh me-revert perubahan belum commit milik orang lain.
Mulai dari service bertipe
Sebelum membuat form, definisikan kontrak API. Dengan begitu component fokus pada state UI dan service fokus pada komunikasi.
import { HttpClient } from '@angular/common/http';
import { inject, Injectable } from '@angular/core';
import { Observable } from 'rxjs';
export type TicketPriority = 'low' | 'medium' | 'high';
export interface TicketDraft {
title: string;
email: string;
priority: TicketPriority;
message: string;
}
export interface Ticket extends TicketDraft {
id: string;
createdAt: string;
}
@Injectable({ providedIn: 'root' })
export class TicketService {
private readonly http = inject(HttpClient);
private readonly baseUrl = '/api/tickets';
listTickets(): Observable<Ticket[]> {
return this.http.get<Ticket[]>(this.baseUrl);
}
createTicket(draft: TicketDraft): Observable<Ticket> {
return this.http.post<Ticket>(this.baseUrl, draft);
}
}
Di app standalone, daftarkan HttpClient lewat app.config.ts.
import { ApplicationConfig } from '@angular/core';
import { provideRouter } from '@angular/router';
import { provideHttpClient } from '@angular/common/http';
import { routes } from './app.routes';
export const appConfig: ApplicationConfig = {
providers: [provideRouter(routes), provideHttpClient()],
};
Kesalahan umum adalah service yang menampung endpoint, copy UI, retry, dan state layar sekaligus. Service sebaiknya sederhana: tipe, URL, dan request. Component yang menentukan bagaimana error ditampilkan.
Implementasi Reactive Forms
Contoh berikut memakai Reactive Forms dan signal untuk state saving. Prompt harus menegaskan bahwa ngModel tidak digunakan.
import { Component, computed, inject, signal } from '@angular/core';
import { ReactiveFormsModule, FormControl, FormGroup, Validators } from '@angular/forms';
import { finalize } from 'rxjs';
import { Ticket, TicketService, TicketPriority } from '../../../data/ticket.service';
@Component({
selector: 'app-ticket-intake',
standalone: true,
imports: [ReactiveFormsModule],
template: `
<form [formGroup]="form" (ngSubmit)="submit()" aria-label="Support ticket form">
<label>Title <input type="text" formControlName="title" /></label>
<label>Email <input type="email" formControlName="email" /></label>
<label>
Priority
<select formControlName="priority">
<option value="low">Low</option>
<option value="medium">Medium</option>
<option value="high">High</option>
</select>
</label>
<label>Message <textarea formControlName="message"></textarea></label>
@if (form.hasError('submit')) {
<p role="alert">Ticket could not be saved. Please try again.</p>
}
@if (savedTicket(); as ticket) {
<p role="status">Saved ticket {{ ticket.id }}</p>
}
<button type="submit" [disabled]="isSubmitDisabled()">
{{ saving() ? 'Saving...' : 'Create ticket' }}
</button>
</form>
`,
})
export class TicketIntakeComponent {
private readonly ticketService = inject(TicketService);
readonly saving = signal(false);
readonly savedTicket = signal<Ticket | null>(null);
readonly form = new FormGroup({
title: new FormControl('', { nonNullable: true, validators: [Validators.required, Validators.minLength(5)] }),
email: new FormControl('', { nonNullable: true, validators: [Validators.required, Validators.email] }),
priority: new FormControl<TicketPriority>('medium', { nonNullable: true }),
message: new FormControl('', { nonNullable: true, validators: [Validators.required, Validators.minLength(20)] }),
});
readonly isSubmitDisabled = computed(() => this.form.invalid || this.saving());
submit(): void {
this.form.markAllAsTouched();
this.form.setErrors(null);
if (this.form.invalid) return;
this.saving.set(true);
this.ticketService.createTicket(this.form.getRawValue()).pipe(
finalize(() => this.saving.set(false)),
).subscribe({
next: (ticket) => {
this.savedTicket.set(ticket);
this.form.reset({ title: '', email: '', priority: 'medium', message: '' });
},
error: () => this.form.setErrors({ submit: true }),
});
}
}
Tiga pitfall yang sering muncul: mencampur ngModel dan formControlName, lupa menonaktifkan tombol saat saving, dan mengirim form.value yang bisa berisi nilai nullable. Gunakan control nonNullable dan getRawValue().
Use case praktis
Use case pertama adalah form back office. Prompt harus menyebut field, validation, state saving, success message, dan failure message.
Use case kedua adalah memindahkan HTTP call dari component lama ke service. Minta Claude Code membuat tipe, memindahkan HttpClient, memisahkan copy UI, dan menambahkan HttpClient test.
Use case ketiga adalah bug fix dengan regression test. Jika API failure membuat tombol tetap disabled, berikan langkah reproduksi, ekspektasi, dan command test.
Use case keempat adalah migrasi bertahap dari NgModule ke standalone. Batasi satu feature folder, jangan ubah routing/provider, dan jalankan test setelah setiap langkah.
Unit test, E2E, dan review
Test HttpClient tidak boleh mengakses network asli.
import { TestBed } from '@angular/core/testing';
import { provideHttpClient } from '@angular/common/http';
import { provideHttpClientTesting, HttpTestingController } from '@angular/common/http/testing';
import { TicketService } from './ticket.service';
describe('TicketService', () => {
let service: TicketService;
let http: HttpTestingController;
beforeEach(() => {
TestBed.configureTestingModule({
providers: [TicketService, provideHttpClient(), provideHttpClientTesting()],
});
service = TestBed.inject(TicketService);
http = TestBed.inject(HttpTestingController);
});
afterEach(() => http.verify());
it('creates a ticket through the API', () => {
const draft = {
title: 'Billing export is stuck',
email: 'ops@example.com',
priority: 'high' as const,
message: 'The monthly billing export has not finished for two hours.',
};
service.createTicket(draft).subscribe((ticket) => expect(ticket.id).toBe('T-100'));
const req = http.expectOne('/api/tickets');
expect(req.request.method).toBe('POST');
expect(req.request.body).toEqual(draft);
req.flush({ ...draft, id: 'T-100', createdAt: '2026-06-02T09:00:00.000Z' });
});
});
Untuk E2E, gunakan ng e2e jika workspace punya target, atau Playwright jika itu standar tim. Minimal cek halaman terbuka, field bisa diisi, API response dikontrol, dan pesan sukses muncul.
Review diff Angular ini secara kritis.
Cek standalone imports/providers, nullable value di Reactive Forms, double submit,
batas service/UI, HttpClient tests, coverage unit/E2E, penggunaan any,
subscription tidak perlu, dan accessibility issue.
Kembalikan issue dengan file, line, dan prioritas.
Hasil dan CTA
Saat dicoba di project Angular kecil, prompt yang terlalu umum menghasilkan campuran ngModel, UI copy di service, dan tidak ada failure test. Setelah tugas dipecah menjadi analisis, service, form, HTTP test, E2E, dan review, diff jauh lebih mudah diperiksa. Untuk tim, tulis aturan ini di CLAUDE.md dan gunakan training dan konsultasi Claude Code agar workflow review bisa diulang.
PDF gratis: cheatsheet Claude Code
Masukkan email dan unduh satu halaman berisi command, kebiasaan review, dan workflow aman.
Kami menjaga datamu dan tidak mengirim spam.
Tentang penulis
Masa
Engineer yang berfokus pada workflow Claude Code praktis dan adopsi tim.
Artikel terkait
Workflow Obsidian ke CLAUDE.md untuk Claude Code
Ubah catatan kerja Obsidian menjadi operating note CLAUDE.md agar konteks tidak dijelaskan ulang.
Claude Code Revenue CTA Routing: dari artikel ke PDF, Gumroad, dan konsultasi
Workflow Claude Code untuk mengarahkan pembaca ke PDF gratis, Gumroad, atau konsultasi sesuai intent.
Aturan handoff tim Claude Code: bukti review, permission, rollback, dan jalur revenue
Format handoff Claude Code untuk tim: bukti, permission rule, rollback, PDF gratis, Gumroad, dan konsultasi.