Introduction
In this post, I will show you how to create a CRUD application in Angular, that allows you to create, update and delete records from the table itself.
This project is suited for beginners.
You can find the repository for the project on my [GitHub] by clicking here.
Please note, this application will not be integrated with a database and is for demonstration purposes only. So let’s get started.
Initialize the project setup.
Firstly, we need to ensure that you have Nodejs, NPM and Angular installed. You can check this by opening a new terminal and running the following commands:
node -v
npm -v
ng version
If you haven’t yet installed any of these, I would recommend you check out this guide.
Now let’s create our application. In your terminal, run the following command.
ng new inline-table-editor
Then, navigate into your project and open up the file in your code editor of choice.
Now that the application has been created, we’ll need to install and set up the UI library which in this case is going to Bootstrap. Install NGXBootstrap:
ng add ngx-bootstrap
Next, we’ll need to add the Bootstrap & Bootstrap Icons CSS libraries into the application. To do so, navigate to the index.html page, and in the <head>
section add the following code:
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css">
<!-- Bootstrap Icons CSS -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.5.0/font/bootstrap-icons.css">
With that, the project is ready to go.
Create the Users table.
Let’s get started by creating the user's table. First, we’ll need to define our data model. In the root of the src folder, create a new folder names models. And add a new file titled: “Users.ts”. In the Users file add the following code to define the Users interface:
export interface User {
id: string;
firstName: string;
lastName: string;
email: string;
}
Next, we’ll seed some demo data into the table. To generate some demo data, you can checkout JSON Generator. Once you’ve opened the window, replace the code in the left tab with the following code and hit generate.
[
'{{repeat(8)}}',
{
id: '{{objectId()}}',
firstName: '{{firstName()}}',
lastName: '{{surname()}}',
email: '{{email()}}',
}
]
This will generate 8 random objects that can then be copied to your clipboard. Then navigate back to our application and in app.component.ts
file, create a new variable and paste your mock data.
user: User[] = [
// paste your generated content here.
]
It’s worth pointing out that in real-life applications, the data would be stored in a database and retrieved once needed using an API.
Now with that completed, navigate to the app.component.html
file and replace all the existing code with the following to create the table.
<div class="container">
<table class="table">
<thead>
<tr>
<th scope="col">Id</th>
<th scope="col">First Name</th>
<th scope="col">Last Name</th>
<th scope="col">Email Address</th>
<th>
<button
type="button"
title="Add New User"
class="btn btn-primary"
>
<i class="bi bi-plus"></i>
</button>
</th>
</tr>
</thead>
<tbody>
<ng-container *ngFor="let user of users; let i = index">
<tr>
<td>{{ user.id }}</td>
<td>{{ user.firstName }}</td>
<td>{{ user.lastName }}</td>
<td>{{ user.email }}</td>
<td>
<button
class="btn btn-danger btn-sm mx-1"
title="Delete User"
type="button"
>
<i class="bi bi-trash"></i>
</button>
</td>
</tr>
</ng-container>
</tbody>
</table>
</div>
Once completed, run the application and navigate to http://localhost:4200, view your table with the demo data inside of it.
ng serve
Updating an Existing User
To perform updates to the data, we’ll be making use of the Reactive Forms Module that’s built in angular. Firstly, add the ReactiveFormsModule
to you application in the app.module.ts
file.
imports: [
// Existing Modules
ReactiveFormsModule,
],
Next we’ll need to add a constructor to our app.component.ts
file and inject the Form Builder, which is used to build our reactive forms.
constructor(
private fb: FormBuilder
) { }
Now, we’ll create our form with the needed fields and validation requirements.
form = this.fb.group({
firstName: ['', [Validators.required]],
lastName: ['', [Validators.required]],
email: ['', [Validators.required, Validators.email]]
});
I’m planning on creating more content based on the Reactive Forms Module. Sign up to my newsletter for my latest updates.
With this application, you can update any user by just clicking on them. However, we want to make sure that the user is only able to make changes to once user at a time. To accomplish that, we’ll create a property, userSelected
and a method called selectUser()
to select a user to select the user that is too be updated.
userSelected: User = {} as User;
selectUser(user: User) {
// check if userSelected is empty, before assigning a selected user
if(Object.keys(this.userSelected).length === 0) {
this.userSelected = user;
this.form.patchValue({
firstName: user.firstName,
lastName: user.lastName,
email: user.email
})
}
}
Next, we’ll need to let the UI respond to us selecting a user. For this I want the background color of the row to change and replace the table data with inputs. To achieve this, replace the code in the <tbody>
with the following.
<tbody>
<ng-container *ngFor="let user of users; let i = index">
<tr
*ngIf="userSelected != user"
(click)="selectUser(user)"
>
<td>{{ user.id }}</td>
<td>{{ user.firstName }}</td>
<td>{{ user.lastName }}</td>
<td>{{ user.email }}</td>
<td>
<button
class="btn btn-danger btn-sm mx-1"
title="Delete User"
type="button"
>
<i class="bi bi-trash"></i>
</button>
</td>
</tr>
<tr *ngIf="userSelected == user" class="table-primary">
<td>{{ user.id }}</td>
<td>
<input
type="text"
class="form-control"
formControlName="firstName"
[value]="user.firstName"
title="First Name"
/>
</td>
<td>
<input
type="text"
class="form-control"
formControlName="lastName"
[value]="user.lastName"
title="Last Name"
/>
</td>
<td>
<input
type="text"
class="form-control"
formControlName="email"
[value]="user.email"
title="Email Address"
/>
</td>
<td>
<button
class="btn btn-primary btn-sm mx-1"
title="update"
type="submit"
[disabled]="form.invalid"
>
<i class="bi bi-lightning"></i>
</button>
<button
class="btn btn-danger btn-sm mx-1"
title="Cancel Changes"
type="button"
>
<i class="bi bi-x-lg"></i>
</button>
</td>
</tr>
</ng-container>
</tbody>
To summarize this code, it checks if the user selected is the user that is in the row of the table. If so, we change the background color of the row and add in the form inputs needed. It’s important to note that this code the form above will not work. To do that, we’ll need to wrap our table in a <form>
tag.
<form [formGroup]="form" (ngSubmit)="update()">
<table class="table">
</table>
</form>
Now let’s create the update()
to update the user.
update() {
// gets the index of the user we need to update
let index = this.users.map(u => u.id).indexOf(this.userSelected.id);
// updates the user at the index selected
this.users[index] = {
id: this.userSelected.id,
firstName: this.form.value.firstName!,
lastName: this.form.value.lastName!,
email: this.form.value.email!
};
// clean up
this.userSelected = {} as User;
this.form.reset();
}
Finally, we’ll need the “Cancel Changes” button to undo the changes and reset the UI.
<!-- Cancel Changes Button in app.component.html -->
<button
class="btn btn-danger btn-sm mx-1"
title="Cancel Changes"
type="button"
(click)="cancel()"
>
<i class="bi bi-x-lg"></i>
</button>
// app.component.ts
cancel() {
// clears the user selected
this.userSelected = {} as User;
// resets the form
this.form.reset();
}
Create a new User
To create a new user, we’ll use a lot of the same methods and functionality that we’ve already built in. Let’s start by adding the isEditing
property. This property will distinguish between if we’re currently editing an existing user or adding a new one. Add the isEditing
variable to the top of the app.component.ts
.
isEditing: boolean = false
Next, let’s make changes to our existing code to update the functionality. Replace the existing methods in the app.component.ts
with the code below.
selectUser(user: User) {
if(Object.keys(this.userSelected).length === 0) {
this.userSelected = user;
this.isEditing = true
this.form.patchValue({
firstName: user.firstName,
lastName: user.lastName,
email: user.email
})
}
}
update() {
if(!this.isEditing) {
this.users[0] = {
id: this.generateId(),
firstName: this.form.value.firstName!,
lastName: this.form.value.lastName!,
email: this.form.value.email!
}
}
else {
let index = this.users.map(u => u.id).indexOf(this.userSelected.id);
this.users[index] = {
id: this.userSelected.id,
firstName: this.form.value.firstName!,
lastName: this.form.value.lastName!,
email: this.form.value.email!
};
}
// clean up
this.userSelected = {} as User;
this.isEditing = false
this.form.reset();
}
cancel() {
if(!this.isEditing && confirm('All unsaved changes will be removed. Are you sure you want to cancel?')) {
// removes the user that was added
this.users.splice(0, 1);
}
this.userSelected = {} as User;
this.isEditing = false
this.form.reset();
}
We’ll also need to add another method to generate an ID for the user. In a real world scenario, this would be generated by the backend or database.
// Generates a random string of characters.
generateId() {
return (Math.random() + 1).toString(36).substring(4) + (Math.random() + 1).toString(36).substring(4)
}
Finally, let’s create the addUser()
to set add our new user to the frontend.
<!-- Add New User button, app.component.html -->
<button
type="button"
title="Add New"
class="btn btn-primary"
(click)="addUser()"
>
<i class="bi bi-plus"></i>
</button>
// app.component.ts
addUser() {
this.users.unshift({
id: '-',
firstName: '',
lastName: '',
email: ''
})
this.userSelected = this.users[0];
}
Deleting a User
To finalize all the CRUD functionality, we’ll need to create a way to delete a user.
<!-- Delete User button, app.component.html -->
<button
class="btn btn-danger btn-sm mx-1"
title="delete"
type="button"
(click)="deleteUser(i)"
>
<i class="bi bi-trash"></i>
</button>
// app.component.ts
deleteUser(index: number) {
if(confirm('Are you sure you want to delete this user?')) {
this.users.splice(index, 1);
}
}
Conclusion
I hope you found this post useful.
Be sure to check me out on Twitter for more Angular and development tips. Thanks for reading and have a great day! 😄