Styling and Refinements
The application is mostly done now, all we have left to do is a few final refinements and style tweaks.
Adding Delete Functionality
Once again, we are going to use the same strategy as we did in Quicklists to delete photos from this application. We will add a method to support deleting and then trigger that delete using sliding list items.
However, there is one interesting aspect to this and that is: in the case of the application running natively, the photo will be stored in the native filesystem. We can just delete the entry from our StorageService
using the Ionic Storage API, but that would only remove the path to that photo. The photo itself will still exist on the device (we can just no longer access it). To properly clean up after ourselves, we are going to again use the Filesystem
API to remove the photo on the device if it exists.
Add the following method to the
PhotoService
:
async deletePhoto(name: string) {
const newPhotos = this.#photos$.value.filter(
(photos) => photos.name !== name
);
this.#photos$.next(newPhotos);
if (this.platform.is('capacitor')) {
await Filesystem.deleteFile({
path: name,
directory: Directory.Data,
});
}
}
The first half of this method is standard - we remove the photo and emit the new values. In the second half we check to see if this is running natively, and if it is we use the deleteFile
method from the Filesystem
plugin to remove the photo from the native file system as well.
Now we are going to modify our PhotoListComponent
to use sliding list items and to emit an event when an item is selected to be deleted. Remember that we want to handle the actual deletion in the parent HomeComponent
file which is why we create a deleted
output on our dumb component, rather than just having the dumb component delete the item directly (because then it wouldn’t be a dumb component anymore!).
Add the following output to the
PhotoListComponent
:
@Output() delete = new EventEmitter<string>();
I will paste the code for updating to use the ion-item-sliding
component in just a moment. However, this would be a good exercise if you want to try and do it for yourself (it is the same as what we did in the Quicklists application). Use the ion-item-sliding
component (refer to the documentation if you need) to add a button beneath the photo items. Also trigger the delete
output that we just added when this button is clicked.
Click here to reveal solution
Solution
Modify the
PhotoListComponent
template to reflect the following:
<ion-list lines="none">
<ion-item-sliding *ngFor="let photo of photos; trackBy: trackByFn">
<ion-item>
<img [src]="photo.safeResourceUrl" />
<ion-badge slot="end" color="light">
{{ photo.dateTaken | daysAgo }}
</ion-badge>
</ion-item>
<ion-item-options side="end">
<ion-item-option (click)="delete.emit(photo.name)" color="danger">
<ion-icon name="trash" slot="icon-only"></ion-icon>
</ion-item-option>
</ion-item-options>
</ion-item-sliding>
</ion-list>
Finally, we will need to handle this delete
output in our HomeComponent
.
Update the
HomeComponent
to call thedeletePhoto
method in response to thedelete
event:
<app-photo-list
[photos]="vm.photos"
(delete)="photoService.deletePhoto($event)"
></app-photo-list>
You should now be able to delete photos (note that you will need the mobile emulation in the Chrome DevTools enabled in order to slide the photos - if you try to drag the items without having the emulator enabled it will just drag the actual image).
Presenting Element for Modal
We are again going to make a similar improvement to our Quicklists application and add in the presentingElement
option for our modal to make it look a bit nicer.
Add the
presentingElement
option to the modal inHomeComponent
:
<ion-modal
[isOpen]="vm.modalIsOpen"
[canDismiss]="true"
[presentingElement]="routerOutlet.nativeEl"
(ionModalDidDismiss)="modalIsOpen$.next(false)"
>