Angular: How to make a contact list — Part 1

María Peña
8 min readOct 26, 2022

--

Creating a simple contact list with Angular

Article banner

The objective

Today I am going to show you how to build a simple contact list using Angular. The web app will allow you to create new contacts, edit and delete existing ones, and see the total amount of contacts you currently have.

Screenshot of how the app will look

Here is the app in StackBlitz in case you want to take a look at it before starting:

What we will use:

For this project I will be using Angular, and some components from Angular Material to save some time. The objectives can be achieved without the use of Material, but I find it easier than creating the styles from scratch.

Step by step

1. File structure

For the file structure, I first initialized an Angular project. I then created a “components” folder inside the app folder, where I created a module called “contact-list”, and a folder called “new-contact”, which will contain the dialog that opens for creating/editing a new contact. So to summarize, the components I will be using are:

  • contact-list.component.ts
  • new-contact.component.ts
  • app.component.ts

In stackblitz, we can easily use the Angular Generator to create new components easily. If you are working in a code editor such as Visual Studio Code, you can use the command: ng generate component <component-name> to create new components.

Once you have created the components and modules, you must import contact-list.module into the app.module. We will also be using Reactive Forms, so we will just go ahead and import this as well.

app.module.ts:

import { NgModule } from '@angular/core';import { BrowserModule } from '@angular/platform-browser';import { FormsModule, ReactiveFormsModule } from '@angular/forms';import { AppComponent } from './app.component';import { ContactListModule } from './components/contact-list/contact-list.module';import { BrowserAnimationsModule } from '@angular/platform-browser/animations';@NgModule({imports: [BrowserModule,FormsModule,ContactListModule,BrowserAnimationsModule,ReactiveFormsModule,],declarations: [AppComponent],bootstrap: [AppComponent],})export class AppModule {}

We must also declare the two components we have created in the contact-list.module, and export our main component.

contact-list.module.ts

import { NgModule } from '@angular/core';import { CommonModule } from '@angular/common';import { ContactListComponent } from './contact-list.component';import { MatListModule } from '@angular/material/list';import { MatIconModule } from '@angular/material/icon';import { MatCardModule } from '@angular/material/card';import { MatDividerModule } from '@angular/material/divider';import { MatButtonModule } from '@angular/material/button';import { MatDialogModule } from '@angular/material/dialog';import { NewContactComponent } from './new-contact/new-contact.component';import { MatInputModule } from '@angular/material/input';import { ReactiveFormsModule } from '@angular/forms';@NgModule({imports: [],declarations: [ContactListComponent, NewContactComponent],exports: [ContactListComponent],})export class ContactListModule {}

2. Connecting Angular Material

Skip this step in case you want to style your css from scratch :)

In my case I´m working on Stackblitz, so all you need to do is write the package name in “Dependencies”, and Stackblitz will take care of the rest. Otherwise, you must follow the steps in the Angular Material documentation to install everything.

The command you will have to run is:

ng add @angular/material

Now that we have Angular Material, all that´s left to do is to import the specific material modules we will be using into the contact module. In our case, we will be using:

  • MatListModule,
  • MatIconModule,
  • MatCardModule,
  • MatDividerModule,
  • MatButtonModule,
  • MatDialogModule,
  • MatInputModule

As well as Reactive Forms. So our contact-list.module will look like this:

contact-list.module.ts

import { NgModule } from '@angular/core';import { CommonModule } from '@angular/common';import { ContactListComponent } from './contact-list.component';import { MatListModule } from '@angular/material/list';import { MatIconModule } from '@angular/material/icon';import { MatCardModule } from '@angular/material/card';import { MatDividerModule } from '@angular/material/divider';import { MatButtonModule } from '@angular/material/button';import { MatDialogModule } from '@angular/material/dialog';import { NewContactComponent } from './new-contact/new-contact.component';import { MatInputModule } from '@angular/material/input';import { ReactiveFormsModule } from '@angular/forms';@NgModule({imports: [CommonModule,MatListModule,MatIconModule,MatCardModule,MatDividerModule,MatButtonModule,MatDialogModule,MatInputModule,ReactiveFormsModule,],declarations: [ContactListComponent, NewContactComponent],exports: [ContactListComponent],})export class ContactListModule {}

In order for Material icons to work, you must link them in the head of your index.html, as so:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Contact List Website</title>
<base href="/" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" type="image/x-icon" href="favicon.ico" />
<link
href="https://fonts.googleapis.com/icon?family=Material+Icons"
rel="stylesheet"
/>
<link
href="https://fonts.googleapis.com/css?family=Karla|Mukta|Poppins"
rel="stylesheet"
/>
</head>
<body>
<my-app>loading</my-app>
</body>
</html>

You must also import an Angular theme. Rename your styles.css to styles.scss, and paste the following line:

@import '@angular/material/prebuilt-themes/deeppurple-amber.css'

You can choose to skip this last part if you do not wish to define an Angular theme, but I recommend you do so since it adds a bit of styling.

In your package.json, change the two lines where we import styles.css, and replace them with:

"styles": ["styles.scss"]

You can check this link to read more on Angular themes.

3. Displaying the component

Now that we have imported the necessary modules, and structured the files, we must display our new component in the app.component. We will do this using a component selector.

The selector for the contact-list.component is app-contact-list, so:

app.component.html

<app-contact-list></app-contact-list>

4. Mockup the main list

Now that we have imported everything we need and created the basic file structure, we will start creating the main list. We will first create a basic mockup with static information, that will then be replaced by our dynamic contacts.

For this mockup I will be using Angular Material components, but feel free to create your own elements with your own styles.

I will create:

  • a header with the title,
  • a paragraph where I will display the total amount of contacts created and a message in case there are no contacts
  • a material list, where each item is a contact
  • a contact item with the contacts: name, address and phone number, as well as a button to edit and one to delete
  • a new contact button
<div class="main-container">
<h1>My contacts</h1>
<p>5 contacts</p>
<mat-list>
<mat-list-item>
<mat-icon matListIcon> person </mat-icon>
<h3 matLine>Maria Peña</h3>
<p matLine>
<span> 143535435</span>
<span class="demo-2"> – My house</span>
</p>
<mat-icon> edit </mat-icon>
<mat-icon> delete </mat-icon>
<mat-divider></mat-divider>
</mat-list-item>
</mat-list>
<button mat-raised-button color="primary">New contact</button>
</div>

5. Create the new-contact dialogue

In step 1 we created a component called new-contact.component. We will now transform this component into a Mat Dialogue, so we can then open it each time the “New contact” button is clicked.

In the constructor we will inject the MatDialogRef reference in order to preform operations such as opening or closing the dialogue.

Since this component will be recieving data from the parent component, we must include a MAT_DIALOG_DATA injection token to access said information.

new-contact.component.ts

import { Component, Inject, OnInit } from '@angular/core';
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
import { ContactItem } from '../contact-list.component';
@Component({
selector: 'app-new-contact',
templateUrl: './new-contact.component.html',
styleUrls: ['./new-contact.component.css'],
})
export class NewContactComponent implements OnInit {
constructor(
public dialogRef: MatDialogRef<NewContactComponent>,
@Inject(MAT_DIALOG_DATA) public data: ContactItem
) {}
ngOnInit() {}
}

We have assigned a type to the input data that will be sent from the parent component. I have declared this type in the contact-list.component:

export interface ContactItem {
firstName: string;
lastName: string;
phone: number;
address: string;
description?: string;
}

Next, we will mockup the dialogue with static information, including a form built with Angular Material form fields:

new-contact.component.html

<div class="dialog-container">
<div class="header">
<h2>New contact</h2>
<mat-icon>close</mat-icon>
</div>
<form>
<mat-form-field appearance="fill">
<mat-label>First name</mat-label>
<input matInput type="text" />
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Last name</mat-label>
<input matInput type="text" />
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Phone number</mat-label>
<input matInput type="number" />
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Address</mat-label>
<input matInput type="text" />
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Description</mat-label>
<textarea matInput></textarea>
</mat-form-field>
</form>
<button mat-raised-button color="primary">Submit</button>
</div>

new-contact.component.css

.header {
width: 100%;
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
}
.dialog-container {
display: flex;
flex-direction: column;
}
form {
width: 100%;
}
.mat-form-field {
width: 100%;
}

6. Opening the dialogue

Now that we have our dialogue component, we must create the logic in the parent component that will allow us to open the modal when the “New contact” button is clicked.

For this, we must inject the MatDialogService via the constructor:

contact-list.component.ts

export class ContactListComponent implements OnInit {
constructor(
public dialog: MatDialog
) {}
ngOnInit() {}
}

Next, we will create a method called newContact():

contact-list.component.ts

newContact() {
this.dialog
.open(NewContactComponent, {
width: '400px',
})
}

Here we are calling the Dialogue Service, and indicating which component we wish to open. We are also passing a width parameter.

7. Creating the contact list

Now that we have a functioning dialogue, it´s time to get started on our list. In our contact-list.component, we will create an Array of Contact Items. When the component first initializes, I am going to add a first contact to the list, just so that it displays something at the very beginning.

contact-list.component.ts

import { Component, OnInit } from '@angular/core';
import { MatDialog } from '@angular/material/dialog';
import { NewContactComponent } from './new-contact/new-contact.component';
export interface ContactItem {
firstName: string;
lastName: string;
phone: number;
address: string;
description?: string;
}
@Component({
selector: 'app-contact-list',
templateUrl: './contact-list.component.html',
styleUrls: ['./contact-list.component.css'],
})
export class ContactListComponent implements OnInit {
contactList: Array<ContactItem> = [];
constructor(public dialog: MatDialog) {}
ngOnInit() {
this.contactList.push({
firstName: 'Maria',
lastName: 'Pena',
phone: 203242,
address: 'Quintana',
description: 'First person',
});
}
newContact() {
this.dialog.open(NewContactComponent, {
width: '400px',
});
}
}

Now that we have a list with an item, we can go ahead and replace the static information in our html with the dynamic contact items. We will use an ngFor to create list items dynamically according to the number of contacts we have, displaying the information for each.

We will also include a first paragraph where we display the length of the list. I have added a ternary operator that determines whether the word will be contact or contacts, depending on the amount of items.

<div class="main-container">
<h1>My contacts</h1>
<p>
{{ contactList.length }} contact{{ contactList.length === 1 ? '' : 's' }}
</p>
<mat-list>
<mat-list-item *ngFor="let item of contactList; let idx = index">
<mat-icon matListIcon> person </mat-icon>
<h3 matLine>{{ item.firstName }} {{ item.lastName }}</h3>
<p matLine>
<span> {{ item.phone }} </span>
<span class="demo-2"> – {{ item.address }} </span>
</p>
<mat-icon> edit </mat-icon>
<mat-icon> delete </mat-icon>
<mat-divider></mat-divider>
</mat-list-item>
</mat-list>
<button mat-raised-button color="primary" (click)="newContact()">
New contact
</button>
</div>

We have succesfully

  • created our components,
  • imported the necessary modules,
  • created a Dialogue with a form,
  • created a button that opens that Dialogue
  • created a dynamic list and displayed it

In part 2 we will go on to

  • Create a form group and implement Reactive Forms to create new contacts
  • Edit contacts from the list
  • Delete contacts from the list

Don´t forget to like and subscribe for more tutorials such as this one :), and feel free to comment your questions or opinions on how I could improve this post!

Maria

--

--

María Peña

Web developer – College student – Tech lover. Check my portfolio in www.mariapenadev.com