DEV Community 👩‍💻👨‍💻

Cover image for How to Build a CRUD Application in Angular 14 +
Chadwin Deysel
Chadwin Deysel

Posted on

How to Build a CRUD Application in Angular 14 +

Introduction

Hi there! In this tutorial, I will be going over how you can create a CRUD application in Angular, that utilizes forms in dialogue boxes.

how-to-build-a-crud-application-in-angular-14-+

This tutorial is suitable for those that are new to Angular.

Please note, this tutorial will not be integrated with any database. So, changes made to the data will be temporary.

Project Setup

Firstly, we must 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
Enter fullscreen mode Exit fullscreen mode
npm -v
Enter fullscreen mode Exit fullscreen mode
ng version
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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">
Enter fullscreen mode Exit fullscreen mode

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. Under the app folder, create a new folder called data and then another called users. This is where our seed data and model will live.

Then create a file titled Users.ts and add the following code to define the user:

// src > app > data > users 
export interface User {
    id: number;
    name: string;
    email: string;
    description: string;
    company: string;
}
Enter fullscreen mode Exit fullscreen mode

Next, we’ll seed some demo data into the table. We can use JSON Generator, to generate the seed data for us. Navigate to the page and replace the code in the left tab with the following code and hit generate.

[
  '{{repeat(8)}}',
  {
    id: '{{index()}}',  
    name: '{{firstName()}} {{surname()}}',
    email: '{{email()}}',
    description: '{{lorem()}}',
    company: '{{company()}}'
  }
]
Enter fullscreen mode Exit fullscreen mode

This will generate 8 random objects that can then be pasted into our application. Create another file under the users folder names UsersSeedData.ts, and add the following code:

// src > app > data > users 
export const UsersSeedData: User[] = [
    // paste your generated content here
]
Enter fullscreen mode Exit fullscreen mode

It’s worth pointing out that in real-life applications, the data would be stored in a database and retrieved once need using an API.

Now with that completed, navigate to the app.component.ts file, and make the following changes:

import { User } from 'src/app/data/users/Users';
import { UsersSeedData } from 'src/app/data/users/UsersSeedData

...

// add implements OnInit
export class AppComponent implements OnInit { 
    users: User[] = []

    constructor() {}

    ngOnInit(): void {
        // add the seed data here 
    this.users = UsersSeedData;
  }
}
Enter fullscreen mode Exit fullscreen mode

Next, navigate to the template (app.component.html), and make replace the existing content with the following:

<div class="container">
  <h2>Users</h2>

  <hr>

  <table class="table">
    <thead>
      <tr>
        <th>...</th>
        <th>Name</th>
        <th>Email</th>
        <th>Company</th>
        <th>
          <button 
            class="btn btn-primary mx-1" 
            title="Add New User"
            >
            <i class="bi bi-plus"></i>
          </button>
        </th>
      </tr>
    </thead>

    <tbody>
      <tr *ngFor="let user of users; let i = index">
        <td>{{ i + 1 }}.</td>

        <td>{{ user.name }}</td>
        <td>{{ user.email }}</td>
        <td>{{ user.company }}</td>

        <td>  
          <div>
            <button 
              class="btn btn-primary mx-1" 
              title="Edit User"
              >
              <i class="bi bi-pencil"></i>
            </button>

            <button 
              class="btn btn-danger mx-1" 
              title="Delete User"
              >
              <i class="bi bi-trash"></i>
            </button>
          </div>
        </td>
      </tr>
    </tbody>
  </table>
</div>
Enter fullscreen mode Exit fullscreen mode

Once completed, run the application and navigate to http://localhost:4200, view your table with the demo data inside of it.

ng serve
Enter fullscreen mode Exit fullscreen mode

Creating a New User

As the description of this post mentioned, we’ll be adding our forms to our application using a dialogue box (modal). Let’s start by importing the module that is going to run the modal UI for us. In the app.module.ts file, add make the following changes:

import { ModalModule } from 'ngx-bootstrap/modal';

...

@NgModule({ 
    ...
    imports: [
    // Existing Modules
    ModalModule,
    ],
    ... 
})
Enter fullscreen mode Exit fullscreen mode

Next, navigate back to the app.component.ts and add the following:

modalRef?: BsModalRef;

constructor(
    private modalService: BsModalService
) { }

openModal(template: TemplateRef<any>) {    
  this.modalRef = this.modalService.show(template);
}
Enter fullscreen mode Exit fullscreen mode

We injected the modal service, that is provided by the modal module we imported, and created a method to open the modal. Now in the template, add the following to the bottom of the file:

<ng-template #template>
  <div class="modal-header">
    <h4 class="modal-title pull-left">
      Add New User
    </h4>

    <button type="button" class="btn-close close pull-right" aria-label="Close" (click)="modalRef?.hide()">
      <span aria-hidden="true" class="visually-hidden">&times;</span>
    </button>
  </div>
  <div class="modal-body">
    <form action="#">
      <input 
        type="text"
        title="Full Name"
        placeholder="Full Name"
        class="form-control my-2"
        >

      <input 
        type="text"
        title="Email"
        placeholder="Email"
        class="form-control my-2"
        >

      <input 
        type="text"
        title="Company"
        placeholder="Company"
        class="form-control my-2"
        >

      <textarea
        title="description"
        class="form-control my-2"
        placeholder="Description"
      >

      </textarea>

      <button
        [title]="Add New User"
        class="btn btn-primary"
        type="submit"
      >
        Add New User
      </button>
    </form>
  </div>
</ng-template>
Enter fullscreen mode Exit fullscreen mode

Once that has been added, update the “Add New User”, button with the openModal().

<button 
  class="btn btn-primary mx-1" 
  title="Add New User"
  (click)="openModal(template)"
  >
  <i class="bi bi-plus"></i>
</button>
Enter fullscreen mode Exit fullscreen mode

You can now see that when you click on the “Add New User” button, the modal will pop up with the form inside of it. However, the form does not have any functionality yet. To do that, we’ll be making use of Reactive Forms which comes built-in with Angular. First import the Reactive Forms Module in the app.module.ts file:

import { ReactiveFormsModule } from '@angular/forms';

...

@NgModule({ 
    ...
    imports: [
    // Existing Modules
    ReactiveFormsModule
    ],
    ... 
})
Enter fullscreen mode Exit fullscreen mode

Next, we’ll inject the form builder and build our new form. Navigate to the app.component.ts file, and make the following changes:

... 

form = this.fb.group({ 
    name: new FormControl<string>('', [Validators.required]),
    email: new FormControl<string>('', [Validators.required, Validators.email]),
    description: new FormControl<string>(''),
    company: new FormControl<string>('', [Validators.required])
})

...

constructor(
  private modalService: BsModalService,
  private fb: FormBuilder,
) { }
Enter fullscreen mode Exit fullscreen mode

One thing to note: In Angular 14, a new feature was added called TypedForms. This adds type safety to be added to your forms as well as allows Intellisense, to be used on your form. Now we need to make the necessary changes to our form, to add functionality. In the app.component.html file, replace the contents of the modal with the following:

<ng-template #template>
  <div class="modal-header">
    <h4 class="modal-title pull-left">
      Add New User
    </h4>

    <button type="button" class="btn-close close pull-right" aria-label="Close" (click)="modalRef?.hide()">
      <span aria-hidden="true" class="visually-hidden">&times;</span>
    </button>
  </div>
  <div class="modal-body">
    <form
            [formGroup]="form"
      (ngSubmit)="addUser()"
        >
      <input 
        type="text"
        title="Full Name"
        placeholder="Full Name"
        class="form-control my-2"
                formControlName="name"
        >

      <input 
        type="text"
        title="Email"
        placeholder="Email"
        class="form-control my-2"
                formControlName="email"
        >

      <input 
        type="text"
        title="Company"
        placeholder="Company"
        class="form-control my-2"
                formControlName="company"
        >

      <textarea
        title="description"
        class="form-control my-2"
        placeholder="Description"
                formControlName="description"
      >

      </textarea>

      <button
        [title]="Add New User"
        class="btn btn-primary"
        type="submit"
                [disabled]="form.invalid"
      >
        Add New User
      </button>
    </form>
  </div>
</ng-template>
Enter fullscreen mode Exit fullscreen mode

Finally, let’s create the add addUser(), method to add a new user.

addUser() {
if (this.form.valid) {
  const user: User = { 
    id: this.users.length,
    name: this.form.value.name,
    email: this.form.value.email,
    description: this.form.value.description,
    company: this.form.value.company
  } as User;

  this.users.push(user);

  this.modalRef?.hide();
}
Enter fullscreen mode Exit fullscreen mode

Now we can successfully add a new user!

add-new-user-angular-14-+

Updating an Existing User

To update an existing user, we’re going to make use of the existing functionality used to add a new user. Let’s start by making a modification to the openModal() to pass a user in if there is an existing user. In the app.component.ts file, make the following changes:

openModal(template: TemplateRef<any>, user?: User) {    
  if(user != null) {
        // updates form values if there is a user 
    this.form.patchValue({
      name: user.name,
      email: user.email,
      description: user.description,
      company: user.company
    })
  } else {
        // clears the form if there is no user
    this.form.reset();
  }
  this.modalRef = this.modalService.show(template);
}
Enter fullscreen mode Exit fullscreen mode

Now, we need to make changes to the template. Make the following changes to the “Add New User” button and “Edit User” button, respectively:

...

<button 
    class="btn btn-primary mx-1" 
    title="Add New User"
    (click)="openModal(template, undefined)"
    >
        <i class="bi bi-plus"></i>
</button>

...

<button 
  class="btn btn-primary mx-1" 
  title="Edit User"
  (click)="openModal(template, user)"
  >
  <i class="bi bi-pencil"></i>
</button>
Enter fullscreen mode Exit fullscreen mode

As you can see, in the “Edit User” button, we pass in the user that is being displayed in the table column. However, for the “Add New User” button, we pass in an undefined user that would act as a null user.

We now need to make changes to handle the update functionality, but before we do that, we first need to create a way to detect if we’re updating an existing user or if we’re adding a new user. To do this, we’re going to add another control to the form:

form = this.fb.group({ 
    id: new FormControl<number | null>(null),
    name: new FormControl<string>('', [Validators.required]),
    email: new FormControl<string>('', [Validators.required, Validators.email]),
    description: new FormControl<string>(''),
    company: new FormControl<string>('', [Validators.required])
})
Enter fullscreen mode Exit fullscreen mode

As you can see, we added a nullable form control that corresponds to the ID. Now we need to make our final changes to our openModel(), to add our ID into the form when we pass a user into the method.

openModal(template: TemplateRef<any>, user?: User) {    
    if(user != null) {
      this.form.patchValue({
                // add the users id
        id: user!.id,
        name: user.name,
        email: user.email,
        description: user.description,
        company: user.company
      })
    } else {
      this.form.reset();
    }
    this.modalRef = this.modalService.show(template);
  }
Enter fullscreen mode Exit fullscreen mode

Now we need to update the addUser(), by changing it to updateUsers(), and making changes to the method:

// change addUser() to updateUsers()
updateUsers() {
    if(this.form.value.id != null) {
      if (this.form.valid) {
                // get the index of a user
        const index: number = this.users.findIndex((user: User) => user.id === this.form.value.id);

        if (index !== -1) {
          this.users[index] = {
            id: this.form.value.id,
            name: this.form.value.name,
            email: this.form.value.email,
            description: this.form.value.description,
            company: this.form.value.company
          } as User;
        }

        this.modalRef?.hide();
      }
    }
    else {
      if (this.form.valid) {
        const user: User = { 
          id: this.users.length,
          name: this.form.value.name,
          email: this.form.value.email,
          description: this.form.value.description,
          company: this.form.value.company
        } as User;

        this.users.push(user);

        this.modalRef?.hide();
      }
    }
}
Enter fullscreen mode Exit fullscreen mode

We also need to update our template to use the correct method as well as to indicate that we’re editing a user. in the app.component.html file, replace the modal with the following:

<ng-template #template>
  <div class="modal-header">
    <h4 class="modal-title pull-left">
      {{ form.value.id != null ? 'Edit User' : 'Add New User' }}
    </h4>

    <button type="button" class="btn-close close pull-right" aria-label="Close" (click)="modalRef?.hide()">
      <span aria-hidden="true" class="visually-hidden">&times;</span>
    </button>
  </div>
  <div class="modal-body">
    <form
      [formGroup]="form"
      (ngSubmit)="updateUser()"
    >
      <input 
        type="text"
        title="Full Name"
        placeholder="Full Name"
        class="form-control my-2"
        formControlName="name"
        >

      <input 
        type="text"
        title="Email"
        placeholder="Email"
        class="form-control my-2"
        formControlName="email"
        >

      <input 
        type="text"
        title="Company"
        placeholder="Company"
        class="form-control my-2"
        formControlName="company"
        >

      <textarea
        title="description"
        class="form-control my-2"
        placeholder="Description"
        formControlName="description"
      >

      </textarea>

      <button
        [title]="form.value.id != null ? 'Edit User' : 'Add New User'"
        class="btn btn-primary"
        type="submit"
        [disabled]="form.invalid"
      >
        {{ form.value.id != null ? 'Edit User' : 'Add New User' }}
      </button>
    </form>
  </div>
</ng-template>
Enter fullscreen mode Exit fullscreen mode

Now we can successfully update an existing user!

update-user-angular-14-+

Delete a User

The final part of all of this is to delete a user. Let’s start by updating the “Delete User” button:

<button 
  class="btn btn-danger mx-1" 
  title="Delete User"
  (click)="deleteUser(i)"
  >
  <i class="bi bi-trash"></i>
</button>
Enter fullscreen mode Exit fullscreen mode

As you can see, we pass in the user’s index to the deleteUser(). Finally let’s add the deleteUser(), in the app.component.ts file.

deleteUser(index: number) {
  if(confirm("Are you sure you want to delete this user?")) { 
    const user: User = this.users[index];

    if(user != null) {
      this.users.splice(index, 1);
    }
    else {
      alert("User not found");
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

And with that we can now delete a user and the CRUD functionality is complete.

delete-user-angular-14-+

Conclusion

As always, 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! 😄

Top comments (0)

Timeless DEV post...

How to write a kickass README

Arguably the single most important piece of documentation for any open source project is the README. A good README not only informs people what the project does and who it is for but also how they use and contribute to it.

If you write a README without sufficient explanation of what your project does or how people can use it then it pretty much defeats the purpose of being open source as other developers are less likely to engage with or contribute towards it.