Simple To-do List using Angular CLI

·

0 min read

This is a simple tutorial to help you get hold of angular CLI and angular material by creating a to-do list application. The following application uses Angular Material, Angular CLI and basic HTML, Javascript.

Requirements

  1. Install nodejs and npm depending on your OS. Using this

  2. Install Angular CLI

npm install -g @angular/cli

Get started

We will create a new angular app to-do list and add angular material to the project. It will take quite some time to install all packages so have a cup of coffee and relax.

ng new to-do
cd to-do
npm install --save @angular/material @angular/cdk @angular/animations hammerjs
ng add @angular/material

Click on indigo if you like blue :).

The Angular CLI is a command-line interface tool that you use to initialize, develop, scaffold, and maintain Angular applications.

Angular CLI is like a magic tool. This is one of the ways where angular CLI eases your work, Angular CLI helps you create this hierarchy of folders and files with necessary settings for you to be able to bootstrap your angular application and get started. Pretty cool right!

Features included

  1. Displaying our tasks
  2. Creating a task
  3. Deleting them

This isn't an app with a lot of features so I guess we could just divide it into two components. Let's start by making the toolbar for the app with features to add a task.

We will generate a component for it.

ng generate component toolbar

In short

ng g c toolbar

If you have a large application with different modules you can generate different modules too. In this, we will work with only the root module. In app.module.ts you guys can see there's ToolbarComponent imported.

import {MatToolbarModule} from '@angular/material/toolbar'; import {MatIconModule} from '@angular/material/icon'; import {MatButtonModule} from '@angular/material/button';

@NgModule({
  declarations: [
    AppComponent,
    ToolbarComponent,
  ],
  imports: [
    BrowserModule,
    BrowserAnimationsModule,
    MatToolbarModule,
    MatIconModule,
    MatButtonModule,

  ],
  providers: [],
  bootstrap: [AppComponent]
})

First well design the toolbar so the html file corresponding to this component is toolbar.component.html. So now what we want is when we click on the add button we want a pop up or somthing to ask us to add a task.

<mat-toolbar color="primary" >
    <span class="toolbar">To-do list</span>
  </mat-toolbar>
<footer>
    <mat-toolbar color="primary" >
        <div class="btn">
            <button mat-fab color="accent">
              <mat-icon class="plus">add</mat-icon>
            </button>
          </div>
    </mat-toolbar>
</footer>

toolbar.component.css

.toolbar{
    font-family: 'Gill Sans', 'Gill Sans MT', Calibri, 'Trebuchet MS', sans-serif;
    color: white;
    text-align: center;
    flex: 1 1 auto;
}
footer{
    position: fixed;
    bottom: 0;
    width:100%;
}
.btn
{
    position: fixed;
    right:5px;
    bottom: 30px;
}
.plus{
    scale: 1.5;
}

style.css

@import "~@angular/material/prebuilt-themes/indigo-pink.css";

<button mat-fab color="accent" (click)="openDialog()"> So when we click on the button we want a dialog box to open,

import this in your toolbar.component.ts

import {MatDialog} from '@angular/material/dialog';

So we need to get the task number(I'll tell why this is important later), the title of the task and an array to store these. So in class on toolbar.component.ts

export class ToolbarComponent implements OnInit {
  title: string="";
  id : number;
  todos = [{id:0, title: " "}];
  constructor(public dialog: MatDialog) {}
  ngOnInit(): void {}

Now we need another component to take these tasks and display them.Type the following cli command in your terminal.

ng g c task-list

So after clicking on the button, we want the dialog box to open, After this, your next component will take care of taking in data and displaying it

So the toolbar will have UI to add the data and Task-list will display the data. Since even task-list needs to use the same variables we will export it as an interface.

Just below the import statement in toolbar.component.ts add

export interface DialogData {
  title : string;
  todos : any[ ];
  id : number;
}

Since you exported it , import it in tasklist along with few other angular dialog material

import { DialogData } from '../toolbar/toolbar.component'; import { Component, OnInit, Inject } from '@angular/core'; import {MatDialogRef, MAT_DIALOG_DATA} from '@angular/material/dialog';

In typescript we usually write names in the camel case, if you have noticed, even id you have written task-list, the component name will be TaskList.

In toolbar we will import tasklist component.

import { TaskListComponent } from '../task-list/task-list.component';

In tasklist class add this in contructor

constructor(
    public dialogRef: MatDialogRef<TaskListComponent>,
    @Inject(MAT_DIALOG_DATA) public data: DialogData) {}

The MatDialogRef provides a handle on the opened dialog. It can be used to close the dialog and to receive a notification when the dialog has been closed.

toolbar.component.ts in class

openDialog(): void {
    const dialogRef = this.dialog.open(TaskListComponent, {
      width: '300px',
      data: {id: this.id,title: this.title}
    });
  }

A dialog is opened by calling the open method with a component to be loaded and an optional config object. The open method will return an instance of MatDialogRef. Components created via MatDialog can inject MatDialogRef and use it to close the dialog in which they are contained. Inject lets you add dependencies and services to the component. @Inject() is alike a manual mechanism for letting Angular know that a parameter must be injected.

To share data with your dialog, we are using the data option to pass information to the dialog component.

Here we want to pass the id and title of the task.

We also have to tell what should happen after we close the dialog box

dialogRef.afterClosed().subscribe(result => {
      this.todos.push(result);
      console.log(this.todos);
      this.title= result;
    });

What we want to do is push the data in our array.

openDialog(): void {
    const dialogRef = this.dialog.open(TaskListComponent, {
      width: '300px',
      data: {id: this.id,title: this.title}
    });
    dialogRef.afterClosed().subscribe(result => {
      this.todos.push(result);
      console.log(this.todos);
      this.title= result;
    });
  }

We will be using formfield for input and to display we will use cards.

app.module.ts

import {MatCardModule} from '@angular/material/card'; import {MatFormFieldModule} from '@angular/material/form-field'; import{ FormsModule} from '@angular/forms';

import these in import array

MatCardModule,MatFormFieldModule,FormsModule

tasklist.component.html

<h1 mat-dialog-title>Add To-do</h1>
<div mat-dialog-content>
    <p>Task Number:</p>
    <mat-form-field>
      <input matInput [(ngModel)]="data.id">
    </mat-form-field>
  <p>What's your new routine?</p>
  <mat-form-field>
    <input matInput [(ngModel)]="data.title">
  </mat-form-field>
</div>
<div mat-dialog-actions>
  <button mat-button (click)="onNoClick()">Cancel</button>
  <button mat-button  [mat-dialog-close]="data">Add</button>
</div>

ngModel is used for two-way binding.

[mat-dialog-close]="data"

Will close the dialog box and return the data in the input, if you click cancel it should just go back to the original page.

onNoClick() lets make a function for this in tasklist.component.ts class after the constructor.

onNoClick(): void {
    this.dialogRef.close();
  }

Like i said why we need id number is to delete the task, if you have id then it is just 1 line code to delete the task. In the class of toolbar.component.ts

delete(id:number)
  {
    this.todos.splice(id,1);
  }

Now only thing left is to display it on the main screen. In toolbar.component.html between the toolbars we can add the following.

<ol>
  <mat-card class="card" ><li *ngFor="let todo of todos">

          <mat-card-title *ngIf="todo.id">Task:{{todo.id}}</mat-card-title>
          <mat-card-content *ngIf="todo.id">
            <button mat-icon-button (click)="delete(todo.id)" >
              <mat-icon>delete</mat-icon>
            </button>
            {{todo.title}}
          </mat-card-content>
      </li>

  </mat-card>
  </ol>

Below is the link to the Github repo of the above implementation. Thank you for taking the time to read this tutorial hopefully this was helpful.

Github URL: https://github.com/IE-NITK/MEAN-SMP-2020/tree/master/Simple-todo-list%20app/list

To run the above project

Clone the project and move into the "list" directory and type the following commands on your terminal.

npm install
ng serve