Adding create, edit and delete functionality

Now we have the form lets make sure it functions.

Updating the openCreateDialog() method

Inject the admin.service into the admin-catalog.component.ts:

1  private adminService = inject(AdminService);

Update the openCreateDialog() method with the following code in the admin-catalog.component.ts:

1  openCreateDialog() {
2    const dialog = this.dialog.open(ProductFormComponent, {
3      minWidth: '500px',
4      data: {
5        title: 'Create product'
6      }
7    });
8    dialog.afterClosed().subscribe({
9      next: async result => {
10        if (result) {
11          const product = await firstValueFrom(this.adminService.createProduct(result.product));
12          if (product) {
13            this.products.push(product);
14          }
15        }
16      }
17    })
18  }
19

In this code we call the createProduct() method in the admin.service.ts to send up the request to the API ProductsController to create the new product. For the PictureURL just go to https://pixabay.com/images/search/skiing/ (for example) and copy the image url from one of these. We will not be adding image uploading in this specific tutorial.

Test the creation of a new product:

Image
Image

The “weird” id number you see in this screenshot is a consequence of how Sql Server works and how it pre-allocates identity values in blocks and caches them for performance reasons. If the server restarts (and this is a dev Sql server instance so it will have done at least in my case) it can cause the IDs to jump 1000s. To turn off this behaviour you can run the following Sql query against the DB if you wish but it is not really necessary as there is no need for the IDs to be sequential here:

1ALTER DATABASE SCOPED CONFIGURATION SET IDENTITY_CACHE = OFF;

Another thing you might notice is that the pagination does not auto-magically update. There isn’t much we can do about this other than requesting a new batch of products from the API so we will just let this slide on the basis that it is not customer facing functionality.

Creating the edit functionality

Create a new method in the admin-catalog.component.ts:

1  openEditDialog(product: Product) {
2    const dialog = this.dialog.open(ProductFormComponent, {
3      minWidth: '500px',
4      data: {
5        title: 'Edit product',
6        product
7      }
8    })
9    dialog.afterClosed().subscribe({
10      next: async result => {
11        if (result) {
12          await firstValueFrom(this.adminService.updateProduct(result.product));
13          const index = this.products.findIndex(p => p.id === result.product.id);
14          if (index !== -1) {
15            this.products[index] = result.product;
16          }
17        }
18      }
19    })
20  }
21

In this code we pass the selected product to the product-form dialog component as well as an updated title for editing of the product. When the form is submitted we receive the updated product and can then update the products array we have in the admin-catalog by using the findIndex() method to get the product from the array and then replacing it with the updated product.

Update the actions array in the admin-catalog.component.ts to call this new method when the button is clicked:

1  actions = [
2    {
3      label: 'Edit',
4      icon: 'edit',
5      tooltip: 'Edit product',
6      action: (row: any) => {
7        this.openEditDialog(row)
8      }
9    },

The ‘row’ in this case is the product on the row the button is on.

Update the product-form.component.ts as we need to reset the form with the selected product that is about to be edited. Update the ngOnInit() method to access the product and reset the form with the product we are editing:

1  ngOnInit(): void {
2    this.initializeForm();
3    setTimeout(() => {
4      this.loadBrandsAndTypes();
5    })
6    if (this.data.product) {
7      this.productForm.reset(this.data.product)
8    }
9  }

Also update the onSubmit() method so that we include the product.id with the updated products from the form:

1  onSubmit(): void {
2    if (this.productForm.valid) {
3      let product: Product = this.productForm.value;
4      if (this.data.product) product.id = this.data.product.id;
5      this.dialogRef.close({
6        product
7      })
8    }
9  }

You can now test this functionality by updating a product in the catalog which should work correctly:

Image
Image

Adding the delete product functionality

Lets also deal with the deletion of a product. We will use our confirmation service with this one so inject the dialogService we created as part of the main course into the admin-catalog.component.ts:

1  private dialogService = inject(DialogService);

Create a method to open the confirm dialog as well as a delete method to actually delete the product when confirmed:

1  async openConfirmDialog(id: number) {
2    const confirmed = await this.dialogService.confirm(
3      'Confirm delete product',
4      'Are you sure you want to delete this product? This cannot be undone'
5    );
6    if (confirmed) this.onDelete(id);
7  }
8
9  onDelete(id: number) {
10    this.adminService.deleteProduct(id).subscribe({
11      next: () => {
12        this.products = this.products.filter(x => x.id !== id);
13      }
14    })
15  }
16

Then update the actions to call this method:

1  actions = [
2    {
3      label: 'Edit',
4      icon: 'edit',
5      tooltip: 'Edit product',
6      action: (row: any) => {
7        this.openEditDialog(row)
8      }
9    },
10    {
11      label: 'Delete',
12      icon: 'delete',
13      tooltip: 'Delete product',
14      action: (row: any) => {
15        this.openConfirmDialog(row.id)
16      }
17    },

Try deleting the new test product and it should be removed from the list:

Image

Lets also add another button to allow the admin to view the product details from the catalog table. Inject the router so we can route them to this product page in the admin-catalog.component.ts

1  private router = inject(Router);

Add the following to the actions array:

1   actions = [
2    {
3      label: 'View',
4      icon: 'visibility',
5      tooltip: 'View product',
6      action: (row: any) => {
7        this.router.navigateByUrl(`/shop/${row.id}`)
8      }
9    },

You should be able to click on the view button and be taken to the product details page:

Optional challenge

Perhaps you would like the admin to be able to edit the product from the product detail page. See if you can add the functionality to do this using the product form dialog component we have already created in this tutorial. Ensure if you do this the buttons are only visible to the admin, and also give the admin a way to get back to the admin component, as well as ensuring the update is reflected in the details page.

Great, now we have all the CRUD functionality for creating, editing and deleting products, next we will focus on stock control and quantities.