Angular CRUD App
CRUD stands for Create, Read, Update, and Delete. These four actions cover almost everything a data-driven application does. A student record system, a product catalog, and a contact book all rely on them. We build a book manager that talks to a server through the HTTP client. You practice services, components, routing, and forms in one realistic flow.
The Library Counter Idea
Picture a librarian at a counter. A visitor asks to add a new book, find a book, correct a title, or remove a damaged copy. The librarian handles each request and updates the shelf records. Your Angular service plays the librarian. The server holds the records, and the components act as the visitors who make requests.
+-----------+ +-----------+ +-------------+ | Component | --> | Service | --> | Server API | | (screen) | <-- | (HTTP) | <-- | (database) | +-----------+ +-----------+ +-------------+ Create -> POST Read -> GET Update -> PUT Delete -> DELETE
HTTP Methods for Each Action
| Action | HTTP Method | Example Address |
|---|---|---|
| Create | POST | /api/books |
| Read all | GET | /api/books |
| Read one | GET | /api/books/5 |
| Update | PUT | /api/books/5 |
| Delete | DELETE | /api/books/5 |
Step 1: Prepare the Project
Register the HTTP client in your app configuration. Then generate a service and the components for the list and the form.
import { provideHttpClient } from '@angular/common/http';
providers: [provideHttpClient()]
ng generate service book
ng generate component book-list
ng generate component book-formStep 2: Describe the Data
export interface Book {
id?: number;
title: string;
author: string;
}The question mark on id marks it as optional because the server creates the number for new books.
Step 3: Build the Service
The service contains one method for each CRUD action. Each method returns an observable that the component can use.
import { Injectable, inject } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Book } from './book';
@Injectable({ providedIn: 'root' })
export class BookService {
private http = inject(HttpClient);
private url = '/api/books';
getAll() { return this.http.get<Book[]>(this.url); }
getOne(id: number) { return this.http.get<Book>(`${this.url}/${id}`); }
create(book: Book) { return this.http.post<Book>(this.url, book); }
update(id: number, book: Book) { return this.http.put<Book>(`${this.url}/${id}`, book); }
remove(id: number) { return this.http.delete(`${this.url}/${id}`); }
}Step 4: Show the List
The list component loads books when it starts. It displays each row with Edit and Delete buttons.
export class BookListComponent implements OnInit {
private service = inject(BookService);
books = signal<Book[]>([]);
ngOnInit() {
this.service.getAll().subscribe(data => this.books.set(data));
}
delete(id: number) {
this.service.remove(id).subscribe(() =>
this.books.update(list => list.filter(b => b.id !== id)));
}
}The delete method removes the row from the screen only after the server confirms the deletion. This order prevents a mismatch between the page and the database.
Step 5: Build the Form for Create and Update
One form serves both actions. The route tells the component whether it holds a book id. A missing id means a new book. An existing id means an edit.
save() {
const book = this.form.getRawValue();
const request = this.bookId
? this.service.update(this.bookId, book)
: this.service.create(book);
request.subscribe(() => this.router.navigate(['/books']));
}Step 6: Add Routes
export const routes: Routes = [
{ path: 'books', component: BookListComponent },
{ path: 'books/new', component: BookFormComponent },
{ path: 'books/:id/edit', component: BookFormComponent }
];The colon before id marks a changing part of the address. The form component reads that part from the route.
Handle Loading and Empty States
A real screen must handle three moments: waiting for data, showing data, and showing no data. Display a short loading message while the request runs. Show a friendly note such as "No books yet" when the list is empty. These small touches make the application feel finished.
Test with a Fake Server
You may not have a real server yet. The JSON Server package turns a simple file into a working API in one command. It supports all five addresses from the table above, so you can practice immediately.
Practice Exercise
Build the book manager from this lesson. Add a search box above the list that filters books by title. Add a confirmation question before every delete. Run the application and perform all four CRUD actions to confirm that each one reaches the server and updates the screen.
Key Points
- CRUD maps to POST, GET, PUT, and DELETE.
- The service holds all HTTP calls, and components handle the display.
- One form can handle both create and update.
- Show loading and empty states for a polished screen.
