3d cartoon hands holding a phone

Unlock full course by purchasing a membership

Lesson 12

Editing and Deleting Data

Finishing off the CRUD operations

STANDARD

Editing and Deleting Data

The last key feature we need to focus on is the ability to edit and delete the checklists and checklist items. This will involve a reasonably simple extension in terms of the functionality in our services, but updating our user interface to support the new functionality will be a little more involved.

Update the Services

Add the following methods to the ChecklistItemService:

  update(id: string, editedItem: AddChecklistItem) {
    const newItems = this.checklistItems$.value.map((item) =>
      item.id === id ? { ...item, title: editedItem.title } : item
    );

    this.checklistItems$.next(newItems);
  }

  remove(id: string) {
    const modifiedItems = this.checklistItems$.value.filter(
      (item) => item.id !== id
    );

    this.checklistItems$.next(modifiedItems);
  }

  removeAllItemsForChecklist(checklistId: string) {
    const modifiedItems = this.checklistItems$.value.filter(
      (item) => item.checklistId !== checklistId
    );

    this.checklistItems$.next(modifiedItems);
  }

The first two methods here are pretty similar to what we have been seeing so far. To update a checklist item we take the existing values, map them, and if we find an item matching the id passed in we update it with the values from editedItem (otherwise we return the item unchanged).

To remove a checklist item we filter the current values to remove any item that matches the id passed in.

The removeAllItemsForChecklist method is also quite similar, but its purpose might not be immediately obvious. Our ChecklistItemService keeps track of checklist items independently of the actual checklist itself. We then “join” these items to their checklist by using the checklistId field. If you are familiar with relational databases, we are basically using a foreign key to create a many to one relationship.

When we delete a checklist (which we will handle in the ChecklistService) we also want to remove all of the items for that checklist, otherwise the checklist items will remain in storage/memory but since they don’t belong to a checklist anymore they would never be accessible. To deal with this situation, we will call out removeAllItemsForChecklist method whenever we delete a checklist.

Add the following methods to the ChecklistService:

  remove(id: string) {
    const modifiedChecklists = this.checklists$.value.filter(
      (checklist) => checklist.id !== id
    );

    this.checklistItemService.removeAllItemsForChecklist(id);

    this.checklists$.next(modifiedChecklists);
  }

  update(id: string, editedData: AddChecklist) {
    const modifiedChecklists = this.checklists$.value.map((checklist) =>
      checklist.id === id
        ? { ...checklist, title: editedData.title }
        : checklist
    );

    this.checklists$.next(modifiedChecklists);
  }

NOTE: The ChecklistService utilises the ChecklistItemService so you will need to make sure to inject that through the constructor of your service in order for the code above to work. I will leave that for you to implement.

Again, same ideas as usual here - the only key difference being that we are making use of that removeAllItemsForChecklist method.

User Interface for Deleting Checklist

Deleting a checklist or checklist item is going to be easier than editing, so let’s start with that. The general approach we are going to take here is to have our ChecklistList component emit an event when the delete button is clicked on a particular item - just like we did with the toggle event. Then our parent component can listen for that event, and trigger the method in our service as a result.

We will need a delete button of some kind inside of our ChecklistList dumb component, and we know that we are going to need an edit button soon as well, so we have to think about how we want to incorporate that.

Ionic has a really nice component called ion-item-sliding that allows us to easily implement a sliding button with action buttons underneath. You slide the item to the left (or right depending on how it is configured) to reveal action buttons for that item. We are going to use that.

Add the following outputs to the ChecklistList component:

  @Output() delete = new EventEmitter<string>();
  @Output() edit = new EventEmitter<Checklist>();

Modify the template of the ChecklistList to reflect the following:

    <ion-list lines="none">
      <ion-item-sliding
        *ngFor="let checklist of checklists; trackBy: trackByFn"
      >
        <ion-item
          data-test="checklist-item"
          button
          routerLink="/checklist/{{ checklist.id }}"
          routerDirection="forward"
        >
          <ion-label>{{ checklist.title }}</ion-label>
        </ion-item>

        <ion-item-options side="end">
          <ion-item-option color="light" (click)="edit.emit(checklist)">
            <ion-icon name="pencil-outline" slot="icon-only"></ion-icon>
          </ion-item-option>
          <ion-item-option (click)="delete.emit(checklist.id)" color="danger">
            <ion-icon name="trash" slot="icon-only"></ion-icon>
          </ion-item-option>
        </ion-item-options>
      </ion-item-sliding>
    </ion-list>

There are actually multiple components that make up the functionality of ion-item-sliding. We have the ion-item-sliding component that contains everything, and then inside of that we define our ion-item and the ion-item-options which will be the action buttons hidden underneath the item. To make things easier for us later we have also already added the output for edit as well as delete.

Now in the parent HomeComponent we need to respond to the delete event.

Modify the app-checklist-list component in the HomeComponent template to reflect the following:

      <app-checklist-list
        *ngIf="checklists$ | async as checklists"
        [checklists]="checklists"
        (delete)="deleteChecklist($event)"
      ></app-checklist-list>

Add the following method to the HomeComponent class:

  deleteChecklist(id: string) {
    this.checklistService.remove(id);
  }

You should now be able to delete a checklist by sliding the checklist to the left, and choosing the delete button!

User Interface for Deleting Checklist Items

Now we are going to do pretty much the same thing for deleting checklist items.

Add the following outputs to the ChecklistItemList component:

  @Output() delete = new EventEmitter<string>();
  @Output() edit = new EventEmitter<ChecklistItem>();

Modify the ChecklistItemList template to reflect the following:

    <ion-list lines="none">
      <ion-item-sliding
        side="end"
        *ngFor="let item of checklistItems; trackBy: trackByFn"
      >
        <ion-item (click)="toggle.emit(item.id)" color="success">
          <ion-label>{{ item.title }}</ion-label>
          <ion-checkbox
            color="light"
            slot="end"
            [checked]="item.checked"
          ></ion-checkbox>
        </ion-item>

        <ion-item-options>
          <ion-item-option color="light" (click)="edit.emit(item)">
            <ion-icon name="pencil-outline" slot="icon-only"></ion-icon>
          </ion-item-option>
          <ion-item-option color="danger" (click)="delete.emit(item.id)">
            <ion-icon name="trash" slot="icon-only"></ion-icon>
          </ion-item-option>
        </ion-item-options>
      </ion-item-sliding>
    </ion-list>
STANDARD
Key

Thanks for checking out the preview of this lesson!

You do not have the appropriate membership to view the full lesson. If you would like full access to this module you can view membership options (or log in if you are already have an appropriate membership).