How to Build a CRUD Application in Angular 14 +
Tags: angular, webdev, javascript, beginners
Published: 2022-11-29 16:32:30

## 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-+](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ux2hmtkw45u3fmi7imn7.gif)

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
```

```
npm -v
```

```
ng version
```

If you haven’t yet installed any of these, I would recommend you check out [this guide](https://angular.io/guide/setup-local).

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: 

```html
<!-- 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. 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:

```tsx
// src > app > data > users 
export interface User {
    id: number;
    name: string;
    email: string;
    description: string;
    company: string;
}
```

Next, we’ll seed some demo data into the table. We can use [JSON Generator](https://json-generator.com/), 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.

```json
[
  '{{repeat(8)}}',
  {
    id: '{{index()}}',  
    name: '{{firstName()}} {{surname()}}',
    email: '{{email()}}',
    description: '{{lorem()}}',
    company: '{{company()}}'
  }
]
```

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:

```tsx
// src > app > data > users 
export const UsersSeedData: 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 need using an API.

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

```tsx
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;
  }
}
```

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

```html
<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>
```

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

```
ng serve
```

## 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:

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

...

@NgModule({ 
	...
	imports: [
    // Existing Modules
    ModalModule,
	],
	... 
})
```

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

```tsx
modalRef?: BsModalRef;

constructor(
    private modalService: BsModalService
) { }

openModal(template: TemplateRef<any>) {    
  this.modalRef = this.modalService.show(template);
}
```

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:

```html
<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>
```

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

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

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:

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

...

@NgModule({ 
	...
	imports: [
    // Existing Modules
    ReactiveFormsModule
	],
	... 
})
```

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

```tsx
... 

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,
) { }
```

One thing to note: In Angular 14, a new feature was added called [TypedForms](https://angular.io/guide/typed-forms). 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: 

```html
<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>
```

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

```tsx
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();
}
```

Now we can successfully add a new user!


![add-new-user-angular-14-+](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qtqnyubtrud136wb7adv.gif)

## 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: 

```tsx
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);
}
```

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

```html
...

<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>
```

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: 

```tsx
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])
})
```

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.

```tsx
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);
  }
```

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

```tsx
// 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();
      }
    }
}
```

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:

```html
<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>
```

Now we can successfully update an existing user!

![update-user-angular-14-+](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9ouqppb4e29owp92wca6.gif)

## Delete a User

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

```html
<button 
  class="btn btn-danger mx-1" 
  title="Delete User"
  (click)="deleteUser(i)"
  >
  <i class="bi bi-trash"></i>
</button>
```

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.

```tsx
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");
    }
  }
}
```

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


![delete-user-angular-14-+](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ht55rev0u1bikcfbed24.gif)

## 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! 😄