Streamlining Task Management: Building a Dynamic Task List with Firebase Database and CRUD Operations (Part 14) in Your Angular-15 Ionic-7 App
Welcome back to our ongoing series on building a multiplatform application with Angular-15 and Ionic-7! In our previous articles, we have covered a wide range of topics, from authentication to data management. Today, in Part 14, we will explore the creation of a dynamic task list within our app, complete with CRUD (Create, Read, Update, Delete) operations, using Firebase Database.
Task management is a common feature in many applications, and by integrating Firebase Database, we can effortlessly create a dynamic task list that enables users to organize, track, and update their tasks seamlessly. With the powerful combination of Angular-15's framework and Ionic-7's versatility, we can build an app that offers a user-friendly and efficient task management experience.
In this installment, we will guide you through the process of integrating the Firebase Database into our Angular-15 Ionic-7 app to create a dynamic task list. We'll start by setting up the Firebase project and initializing the Firebase Database. Next, we'll design the user interface for the task list, allowing users to view and interact with their tasks.
But we won't stop there. We'll delve into the implementation details, demonstrating how to perform CRUD operations on tasks using Firebase Database. You'll learn how to create new tasks, fetch existing tasks, update task details, and delete unwanted tasks. This functionality will empower your users to effectively manage their tasks within the app.
Throughout this tutorial, we'll emphasize best practices for task organization, user feedback, and error handling. By the end of this article, you'll have a solid understanding of how to leverage Firebase Database to create a dynamic task list with seamless CRUD operations in your Angular-15 Ionic-7 app.
So, join us in Part 14 of our series as we embark on a journey into the world of task management. Together, let's empower our app with the ability to create, update, and delete tasks, offering users a seamless and efficient task management experience. Get ready to take your app's functionality and user experience to the next level!
Tutorial
In this section, I will create the feature Task List where students will be able to enter the tasks they need to do and the tasks they’ve already completed. First, I will begin to add the logic to communicate with the previously set up Firebase cloud database in the already created diary-data.service.ts
file in the following way:
import { Injectable } from '@angular/core';
import {
Firestore, collectionData, collection, docData, doc, addDoc, deleteDoc, updateDoc, DocumentData, getDocs, } from '@angular/fire/firestore';
import { Observable, map } from 'rxjs';
export interface Task {
id?: string;
title: string;
text: string;
done: boolean;
timestamp?: string;
}
@Injectable({
providedIn: 'root',
})
export class DiaryDataService {
constructor(private firestore: Firestore) {} // inject the firestore service
//getTasks from the firestore and filter the tasks that are not done yet and return them as an observable
getTasks(): Observable<Task[]> {
// return an observable of type Task[]
const tasksRef = collection(this.firestore, 'tasks'); // create a reference to the tasks collection
const taskQuery = query(tasksRef, where('done', '==', false)); // filter the tasks that are not done yet
const taskOptions = { idField: 'id' }; // added the idField option to the collectionData operator to get the id of the document
return collectionData(taskQuery, taskOptions) as Observable<Task[]>; // return the tasks that are not done yet
}
// get Task by id from the firestore
getTaskById(id: string): Observable<Task> {
// return an observable of type Task
const taskDocRef = doc(this.firestore, `tasks/${id}`); // create a reference to the task document
return docData(taskDocRef, { idField: 'id' }) as Observable<Task>; // return the task by id
}
// add Task to the firestore and mark it as not done
addTask(task: Task) {
const tasksRef = collection(this.firestore, 'tasks'); // create a reference to the tasks collection
// return addDoc(tasksRef, { ...task, done: false }); // add the task to the firestore and mark it as not done
//add the task to the firestore
return addDoc(tasksRef, task);
}
// delete task from the firestore
deleteTaskById(task: Task) {
const taskDocRef = doc(this.firestore, `tasks/${task.id}`); // create a reference to the task document
return deleteDoc(taskDocRef); // delete the task from the firestore
}
// update task details like the title and text in the firestore
updateSingleTaskById(task: Task) {
const taskDocRef = doc(this.firestore, `tasks/${task.id}`); // create a reference to the task document
return updateDoc(taskDocRef, {
// update the task in the firestore with the new title and text passed in the task object
title: task.title,
text: task.text,
done: task.done, // update the done status of the task
}); // update the task in the firestore with the new title and done passed in the task object
}
//get done tasks from the firestore and return them as an observable of type Task[] to be displayed in the done tasks section
getDoneTasks(): Observable<Task[]> {
// return an observable of type Task[]
const tasksRef = collection(this.firestore, 'tasks'); // create a reference to the tasks collection
const taskQuery = query(tasksRef, where('done', '==', true)); // filter the tasks that are done already
const taskOptions = { idField: 'id' }; // added the idField option to the collectionData operator to get the id of the document
return collectionData(taskQuery, taskOptions) as Observable<Task[]>; // return the tasks that are done already
}
//update the done status of the task in the firestore by passing the task id and event to toggle the done status of the task in the firestore
updateTaskById(taskId: string, event: any) {
const taskDocRef = doc(this.firestore, `tasks/${taskId}`); // create a reference to the task document
return updateDoc(taskDocRef, { done: event.detail.checked }); // update the done status of the task in the firestore // remember to pass the event.detail.checked to the updateDoc method and not just event.detail
}
//delete all the tasks that are done from the firestore by passing the task id and event to toggle the done status of the task in the firestore
async deleteDoneTasks() {
const tasksRef = collection(this.firestore, 'tasks'); // create a reference to the tasks collection
const taskQuery = query(tasksRef, where('done', '==', true)); // filter the tasks that are done already
return getDocs(taskQuery).then((querySnapshot) => {
// get the tasks that are done already
querySnapshot.forEach((doc) => {
// loop through the tasks that are done already
deleteDoc(doc.ref); // delete the task from the firestore
});
});
}}
Here's an overview of what each method in the above code does:
constructor(private firestore: Firestore) {}
: The constructor initializes the class with an instance of Firestore that is injected as a dependency.getTasks(): Observable<Task[]>
: Retrieves a list of tasks from Firestore and returns an observable of typeTask[]
. It uses thecollection()
function to create a reference to the "tasks" collection in Firestore, applies a query to filter out tasks that are marked as done, and returns an observable of the remaining tasks using thecollectionData()
function.getTaskById(id: string): Observable<Task>
: Retrieves a single task by its ID from Firestore and returns an observable of typeTask
. It uses thedoc()
function to create a reference to the specific task document in Firestore and then returns the data for that document using thedocData()
function.addTask(task: Task)
: Adds a new task to Firestore. It uses thecollection()
function to create a reference to the "tasks" collection in Firestore and theaddDoc()
function to add the task to that collection.deleteTaskById(task: Task)
: Deletes a task from Firestore. It uses thedoc()
function to create a reference to the specific task document in Firestore and then deletes that document using thedeleteDoc()
function.updateSingleTaskById(task: Task)
: Updates a single task in Firestore with new details. It uses thedoc()
function to create a reference to the specific task document in Firestore and then updates the title, text, and done status of that document using theupdateDoc()
function.getDoneTasks(): Observable<Task[]>
: Retrieves a list of tasks that are marked as done from Firestore and returns an observable of typeTask[]
. It works similar togetTasks()
, but applies a different query to filter out tasks that are not marked as done.updateTaskById(taskId: string, event: any)
: Updates the done status of a single task in Firestore. It uses thedoc()
function to create a reference to the specific task document in Firestore and then updates the done status of that document based on the value ofevent.detail.checked
. This took me some trial and error to figure out.deleteDoneTasks()
: Deletes all tasks that are marked as done from Firestore. It works similarly to, but retrieves the documents for each task using thegetDocs()
function and then deletes them one by one using thedeleteDoc()
function.
Next, I will import the service logic into the diary.page.ts
which I use for displaying the tasks on the diary page in the following way:
import { Component, OnInit } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import {
AlertController,IonicModule,ModalController,ToastController,
} from '@ionic/angular';
import { DiaryDataService } from 'src/app/services/diary-data.service';
import { RouterLink } from '@angular/router';
import { DiaryTaskModalPage } from '../diary-task-modal/diary-task-modal.page';
import { ItemReorderEventDetail } from '@ionic/angular';
@Component({
selector: 'app-diary',
templateUrl: './diary.page.html',
styleUrls: ['./diary.page.scss'],
standalone: true,
imports: [
IonicModule, CommonModule, FormsModule, DiaryModalPage, RouterLink,
DiaryTaskModalPage,
],
})
export class DiaryPage implements OnInit {
selectTabs: string = 'notes'; // set the default tab
checked: boolean = false; // set the default value of the checked property to false
tasks: any = []; // array of tasks
doneTasks: any = []; // array of done tasks
// Ion Reorder Group Event referred from original ionic documentation
handleReorder(ev: CustomEvent<ItemReorderEventDetail>) {
// The `from` and `to` properties contain the index of the item
// when the drag started and ended, respectively
// console.log('Dragged from index', ev.detail.from, 'to', ev.detail.to);
// Finish the reorder and position the item in the DOM based on
// where the gesture ended. This method can also be called directly
// by the reorder group
ev.detail.complete();
}
constructor(
private diaryDataService: DiaryDataService,
private alertCtrl: AlertController,
private modalCtrl: ModalController,
private toastCtrl: ToastController,
private loadingCtrl: LoadingController
) {
this.diaryDataService.getTasks().subscribe((res) => {
// get the tasks from the diary data service
// console.log(res);
// subscribe to the tasks observable
this.tasks = res; // assign the tasks property to the array of tasks returned by the observable
});
this.diaryDataService.getDoneTasks().subscribe((res) => {
// get the done tasks from the diary data service
// console.log(res);
// subscribe to the done tasks observable
this.doneTasks = res; // assign the done tasks property to the array of done tasks returned by the observable
});
}
ngOnInit() {}
//----------------------Task----------------------//
//open task modal to update task details
async openTask(task: any) {
// open the task
const modal = await this.modalCtrl.create({
// create a modal
component: DiaryTaskModalPage, // set the modal component
componentProps: { id: task.id }, // pass the id of the task to the modal
breakpoints: [0, 0.75, 1], // set the breakpoints
initialBreakpoint: 0.75, // set the initial breakpoint
}); // create a modal
modal.present(); // present the modal
}
// add new task to the list
async addTask() {
// add a task via alert controller
const alert = await this.alertCtrl.create({
// create an alert
header: 'Add Task', // set the header
inputs: [
// array of inputs
{
name: 'title', // input name
type: 'text', // input type
placeholder: 'Enter Your Task Title', // input placeholder
},
{
name: 'text', // input name
type: 'textarea', // input type
placeholder: 'I need to learn react tomorrow...', // input placeholder
},
],
buttons: [
// array of buttons
{
text: 'Cancel', // button text
role: 'cancel', // set to cancel role
cssClass: 'secondary', // set a css class for buttons
handler: () => {
// button handler
console.log('Confirm Cancel');
},
},
{
text: 'Save', // button text
handler: (task) => {
// button handler
// console.log(task);
//get the current date and time
//create a standard date time format
const standardDateTimeFormat = new Intl.DateTimeFormat('en-US', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
});
const currentDate = new Date(); // get the current date and time
const timestamp = standardDateTimeFormat.format(currentDate); // format the date and time to a standard format and assign it to the timestamp variable
this.diaryDataService.addTask({
title: task.title,
text: task.text,
timestamp: timestamp, // add timestamp property to the note object
done: false, // set the done property to false
}); // add the task to the firestore
// console.log(task);
const toast = this.toastCtrl.create({
// create a toast
message: 'Task Added', // set the message
duration: 2000, // set the duration
}); // create a toast
toast.then((toast: any) => toast.present()); // present the toast
},
},
],
}); // create an alert
alert.present(); // present the alert
}
// update the done property of the task
async toggleDone(id: string, event: any) {
// console.log(id);
// console.log(event.detail.checked); // get the checked property of the event
this.diaryDataService.updateTaskById(id, event); // update the done property of the task
//create a toast saying the task is completed
if (event.detail.checked == true) {
// if the task is marked as done create a toast saying the task is completed
const toast = this.toastCtrl.create({
// create a toast
message: 'Task Completed', // set the message
duration: 2000, // set the duration
}); // create a toast
toast.then((toast: any) => toast.present()); // present the toast
} else if (event.detail.checked == false) {
// if the task is marked as undone create a toast saying the task is undone
const toast = this.toastCtrl.create({
// create a toast
message: 'Task Pending', // set the message
duration: 2000, // set the duration
}); // create a toast
toast.then((toast: any) => toast.present()); // present the toast
}
}
//clear all completed tasks from completed tasks list
clearAllCheckedTasks() {
this.diaryDataService.deleteDoneTasks(); // delete all the tasks that are marked as done
const toast = this.toastCtrl.create({
// create a toast
message: 'All Completed Tasks Cleared', // set the message
duration: 2000, // set the duration
}); // create a toast
toast.then((toast: any) => toast.present()); // present the toast
}
}
In the above code, I have initiated the properties: tasks
: an array that holds all tasks added by the user; checked
: a boolean that indicates whether a task is completed or not. Its default value is false; and doneTasks
: an array that holds all completed tasks.
The constructor function subscribes to the getTasks()
and getDoneTasks()
methods of the DiaryDataService
, which are called whenever the DiaryPage
component is created. When these methods are called, the tasks
and doneTasks
properties are updated with the arrays of tasks and done tasks retrieved from the Firestore database.
The handleReorder(ev: CustomEvent<ItemReorderEventDetail>)
method handles a reorder event triggered by the user. It receives a CustomEvent
object as input and calls its complete()
method to complete the reorder and position the item in the DOM. This is used to implement the reorder functionality of the list items referenced from Reorder | ion-reorder: Drag and Drop Icon to Reorder Items (ionicframework.com).
The openTask(task: any)
method opens a modal to update a task's details. It receives a task object as input and creates a modal using the ModalController
module, passing the task's id as a parameter. The modal component used is DiaryTaskModalPage
. This is created using the command: ionic generate page pages/diary-task
and also imported into app.component.ts
file.
The addTask()
method adds a new task to the list. It creates an alert using the AlertController
module with two input fields (title and text) and two buttons (Cancel and Save). When the Save button is clicked, the function gets the current date and time, formats it to a standard date time format, and adds the task object to the Firestore database using the addTask()
method of the DiaryDataService
. Finally, a toast is created using the ToastController
module to confirm that the task has been added to the list.
The toggleDone(id: string, event: any)
method updates the done property of a task when the user marks it as completed via the Ionic Checkbox. It receives the id and event of the task as input and calls the updateTaskById()
method of the DiaryDataService
to update the task's done property in the Firestore database. If the event.detail.checked
property is true, indicating that the task is completed, a toast is created using the ToastController
module to confirm that the task has been completed.
Next, I will implement this logic on the diary.page.html to display the tasks, along with add new button in the following way:
<ion-header [translucent]="false">
<ion-toolbar>
<ion-title>My Diary</ion-title>
<ion-buttons slot="start">
<ion-button routerLink="/tabs/notifications">
<ion-icon slot="icon-only" name="notifications-outline"></ion-icon>
</ion-button>
</ion-buttons>
<ion-buttons slot="end">
<ion-menu-button menu="main-menu"></ion-menu-button>
</ion-buttons>
</ion-toolbar>
</ion-header>
<ion-content [fullscreen]="true">
<ion-header collapse="condense">
<ion-toolbar>
<ion-title size="large">My Diary</ion-title>
</ion-toolbar>
</ion-header>
<!-- Added a segment to the page to allow the user to switch between different pages -->
<!-- Added segments from ionic framework to segment the page into three separate pages all accessible via a segment nav on top -->
<ion-segment [(ngModel)]="selectTabs">
<!-- ngModel is used to bind the value of the segment to the selectTabs variable -->
<ion-segment-button value="schedule">
<ion-label>Schedule</ion-label>
<ion-icon name="calendar-outline"></ion-icon>
</ion-segment-button>
<ion-segment-button value="tasks">
<ion-label>Tasks</ion-label>
<ion-icon name="checkbox-outline"></ion-icon>
</ion-segment-button>
<ion-segment-button value="notes">
<ion-label>Notes</ion-label>
<ion-icon name="document-text-outline"></ion-icon>
</ion-segment-button>
</ion-segment>
<div *ngIf="selectTabs === 'tasks'">
<ion-list lines="full">
<ion-list-header>
<ion-label>
Pending <ion-badge color="primary">{{tasks.length}}</ion-badge>
</ion-label>
<ion-button (click)="addTask()">Add New</ion-button>
</ion-list-header>
<!-- The reorder gesture is disabled by default, enable it to drag and drop items -->
<!-- Casting $event to $any is a temporary fix for this bug <https://github.com/ionic-team/ionic-framework/issues/24245> -->
<ion-reorder-group
[disabled]="false"
(ionItemReorder)="handleReorder($any($event))"
>
<ion-item *ngFor="let task of tasks">
<ion-label (click)="openTask(task)">{{task.title}}</ion-label>
<ion-checkbox
(ionChange)="toggleDone(task.id, $any($event))"
slot="start"
[checked]="task.done"
aria-label="task"
></ion-checkbox>
<ion-reorder slot="end"></ion-reorder>
</ion-item>
</ion-reorder-group>
</ion-list>
<ion-list lines="full">
<ion-list-header>
<ion-label>
Completed <ion-badge color="primary">{{doneTasks.length}}</ion-badge>
</ion-label>
<ion-button (click)="clearAllCheckedTasks()">Clear All</ion-button>
</ion-list-header>
<!-- The reorder gesture is disabled by default, enable it to drag and drop items -->
<!-- Casting $event to $any is a temporary fix for this bug <https://github.com/ionic-team/ionic-framework/issues/24245> -->
<ion-reorder-group
[disabled]="false"
(ionItemReorder)="handleReorder($any($event))"
>
<ion-item *ngFor="let task of doneTasks">
<ion-label
[style.color]="task.done ? 'grey' : 'inherit'"
[style.textDecoration]="task.done ? 'line-through' : 'none'"
(click)="openTask(task)"
>{{task.title}}</ion-label
>
<ion-checkbox
aria-label="task"
slot="start"
[checked]="task.done"
(ionChange)="toggleDone(task.id, $any($event))"
></ion-checkbox>
<ion-reorder slot="end"></ion-reorder>
</ion-item>
</ion-reorder-group>
</ion-list>
</div>
<ion-fab slot="fixed" vertical="bottom" horizontal="end">
<ion-fab-button>
<ion-icon name="add"></ion-icon>
</ion-fab-button>
<ion-fab-list side="top">
<ion-fab-button (click)="addNewEvent()" color="tertiary" size="large">
<ion-icon name="calendar-outline"></ion-icon>
</ion-fab-button>
<ion-fab-button (click)="addTask()" color="tertiary" size="large">
<ion-icon name="checkbox-outline"></ion-icon>
</ion-fab-button>
<ion-fab-button color="tertiary" size="large" (click)="addNote()">
<ion-icon name="document-text-outline"></ion-icon>
</ion-fab-button>
</ion-fab-list>
</ion-fab>
</ion-content>
The above template code defines two lists, one for pending tasks and another for completed tasks, using the <ion-list>
element. The number of tasks in each list is displayed using an <ion-badge>
element with the Angular interpolation syntax ({{}}
) which is referred from Badges | ion-badge: iOS & Android App Notification Badge Icons (ionicframework.com).
Both lists use the <ion-reorder-group>
element to allow the user to drag and drop items to reorder them. The disabled
attribute is set to false
to enable this feature. The ionItemReorder
event is handled by calling the handleReorder
function with the $event
argument.
Each item in both lists is represented by an <ion-item>
element. The task's title is displayed using an <ion-label>
element, which is clickable and opens the task details when clicked. A checkbox element with the ionChange
event bound to the toggleDone
function is used to mark the task as done or not done.
In the completed tasks list, the <ion-label>
element has additional styling applied using the Angular binding syntax ([style.color]
and [style.textDecoration]
) to gray out and add a line-through effect to the task title if it's marked as done.
Next, I will write the logic within the diary-task-modal.page.ts
file for the task update modal in the following way:
import { Component, OnInit } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { IonicModule } from '@ionic/angular';
import { DiaryDataService } from 'src/app/services/diary-data.service';
import { ModalController, ToastController } from '@ionic/angular';
import { Input } from '@angular/core';
import { Task } from 'src/app/services/diary-data.service';
@Component({
selector: 'app-diary-task-modal',
templateUrl: './diary-task-modal.page.html',
styleUrls: ['./diary-task-modal.page.scss'],
standalone: true,
imports: [IonicModule, CommonModule, FormsModule],
})
export class DiaryTaskModalPage implements OnInit {
@Input() id!: string; // id of the task taken from the modal component props
// input decorator is used here to pass the id of the task to the modal component
task!: Task; // task object
constructor(
private diaryDataService: DiaryDataService,
private modalCtrl: ModalController,
private toastCtrl: ToastController
) {}
ngOnInit() {
this.diaryDataService.getTaskById(this.id).subscribe((res) => {
this.task = res; // assign the task property to the task returned by the observable
});
}
//update the task details
async updateTask() {
this.diaryDataService.updateSingleTaskById(this.task); // update the task
//create a toast
const toast = await this.toastCtrl.create({
message: 'Task Updated', // set the message
duration: 2000, // set the duration
});
toast.present(); // present the toast
this.modalCtrl.dismiss(); // dismiss the modal
}
//delete the task
async deleteTask() {
await this.diaryDataService.deleteTaskById(this.task);
//create a toast
const toast = await this.toastCtrl.create({
message: 'Task Deleted', // set the message
duration: 2000, // set the duration
});
toast.present(); // present the toast
this.modalCtrl.dismiss(); // dismiss the modal
}
dismissModal() {
//dismiss the modal
this.modalCtrl.dismiss();
}
}
In the above code, there’s an @Input()
property id
to receive the ID of a task passed in from the parent component. The constructor of this class takes in three parameters: diaryDataService
, modalCtrl
, and toastCtrl
. The ngOnInit()
method is called when the component is initialized and retrieves the task corresponding to the id
input parameter using the getTaskById()
method provided by the diaryDataService
service. When the observable returned by getTaskById()
emits a value, the res
parameter contains the task data, which is assigned to the task
property of the component.
The updateTask()
method is called when the user wants to update the task, and it updates the task data using the updateSingleTaskById()
method provided by the diaryDataService
service. It then displays a toast notification using the toastCtrl
service to confirm the update and dismisses the modal using the modalCtrl
service.
The deleteTask()
method is called when the user wants to delete the task. It deletes the task using the deleteTaskById()
method provided by the diaryDataService
service, displays a toast notification to confirm the deletion, and dismisses the modal.
Finally, the dismissModal()
method is called when the user wants to dismiss the modal without updating or deleting the task. It simply dismisses the modal using the modalCtrl
service.
Next, I will use the above logic to build the HTML template in diary-task-modal.page.html
file in the following way:
<ion-header [translucent]="true"> </ion-header>
<ion-content [fullscreen]="true">
<ion-list lines="full" *ngIf="task">
<ion-item>
<ion-label>{{task.timestamp}}</ion-label>
<ion-icon slot="end" name="close" (click)="dismissModal()"></ion-icon>
</ion-item>
<ion-item>
<ion-label position="stacked">Task</ion-label>
<ion-input aria-label="title" [(ngModel)]="task.title"></ion-input>
</ion-item>
<ion-item>
<ion-label position="stacked">Details</ion-label>
<ion-textarea
aria-label="task"
[(ngModel)]="task.text"
rows="5"
></ion-textarea>
</ion-item>
<ion-item>
<ion-label
>{{task.done ? 'Task is Completed' : 'Task is Pending'}}</ion-label
>
</ion-item>
<ion-button
color="danger"
class="ion-margin"
shape="round"
(click)="deleteTask()"
expand="block"
>
<ion-icon slot="start" name="trash-outline"></ion-icon>
Delete</ion-button
>
<ion-button
shape="round"
class="ion-margin"
color="success"
(click)="updateTask()"
expand="block"
>
<ion-icon slot="start" name="save"></ion-icon> Update</ion-button
>
</ion-list>
</ion-content>
In the above code, the ion-list
component is used to create a list of items in the modal page. The ngIf
directive is used to conditionally render the list only if a task
object is present. Inside the ion-list
, there are four ion-item
components.
The first ion-item
displays the timestamp
property of the task
object and an ion-icon
component with the "close" icon. Clicking on the icon calls the dismissModal()
method on the component.
The second and third ion-item
components create input fields for the title
and text
properties of the task
object using ion-input
and ion-textarea
components, respectively. The [(ngModel)]
directive is used to bind the input fields to the task
object, allowing the user to modify the task details.
The fourth ion-item
displays the status of the task
, either "Task is Completed" or "Task is Pending", depending on the value of the done
property of the task
object.
Two ion-button
components are used to create buttons for deleting and updating the task
. The color
attribute is set to "danger" for the delete button and "success" for the update button. Clicking on the buttons calls the deleteTask()
and updateTask()
methods on the component, respectively.
Finally, the working of above code is demonstrated in Figures 59, 60, 61 & 62 below:
Figure 59: Task List in Diary |
Figure 60: Add New Task Alert Box |
Figure 61: New Task added to pending tasks |
Figure 62: Update & delete task via modal |
Conclusion:
In this fourteenth installment of our series on building a multiplatform application with Angular-15 and Ionic-7, we explored the creation of a dynamic task list with CRUD operations using Firebase Database. By leveraging the power of Firebase Database, we built a robust task management system that enables users to seamlessly organize, update, and track their tasks.
Task management is a crucial feature in many applications, and by integrating Firebase Database into our Angular-15 Ionic-7 app, we empowered users with a user-friendly and efficient task management experience. Users can effortlessly create new tasks, view existing tasks, update task details, and delete unwanted tasks, all within the app.
Throughout this tutorial, we guided you through the process of setting up the Firebase project, initializing Firebase Database, and designing the user interface for the task list. We also covered the implementation details, demonstrating how to perform CRUD operations on tasks using Firebase Database.
We emphasized best practices for task organization, user feedback, and error handling to ensure a seamless and intuitive task management experience. By following these practices, you can create an app that not only enhances productivity but also provides a delightful user experience.
As you move forward, consider exploring additional features and functionalities that can enhance your task management system. You can incorporate features like task sorting, filtering, and task reminders to further improve the user experience. Stay updated with the latest updates from Firebase and Angular to leverage new enhancements and improvements that can enhance your app's task management capabilities.
We hope this tutorial has provided you with valuable insights and practical knowledge on integrating Firebase Database into your Angular-15 Ionic-7 app to create a dynamic task list with CRUD operations. By embracing the power of Firebase Database, you can create an app that offers a seamless and efficient task management experience for your users.
Thank you for joining us on this journey as we explored the fascinating world of app development with Angular-15, Ionic-7, and Firebase Database. Stay tuned for future installments where we will continue to explore new features and functionalities to make our app even more robust and user-friendly.
Happy coding!