Posted by Christian Weiß on July 30, 2018
My first webapp with Angular 6 step by step from scratch. Generated and modified with angular CLI to manage user contacts with CRUD operations on a local JSON Model.
Requirements: Node 8.9 or higher, together with NPM 5.5.1 or higher. For this project, I have npm 6.2.0 and node v9.5.0 installed on my local system.
To install the latest versions of @angular/cli run the command:
npm install -g @angular/cli
To install a specific version, use npm install -g @angular/cli@1.4.9
The following command generates angular 6 project in the current folder.
ng new user-contact
The command create a new folder ‘user-contact’ and a lot of additional stuff.
Once the project is generated, chance to the directory and get started with it. Run following commands to see angular 6 app running at http://localhost:4200
cd user-contact
ng serve -o
'-o' is optinal and starts the browser after the build process is finished
There are certain files generated with CLI command:.
angular.json
File generated contains all the application configuration parameters. The configuration related to welcome html file as index.html, main.ts where all the modules are bundled. You can also find the final application output directory configuration and configuration specific to environment such as dev and prod can be found here.
package.json
File contains information about all the project dependencies.tsconfig.json
for typescript configuration.Inside the scr/app
folder we have our components, services, modules, etc. defined.
If the the sources will be changed the angular CLI recognize it and reloads the browser.
The App needs multiple components such as service and components. Following are the commands to generate our components and service.
ng g component dashboard
ng g component add-usercontact
ng g component edit-usercontact
ng g serice share/usercontact
ng g component my-new-component
ng g directive my-new-directive
ng g pipe my-new-pipe
ng g service my-new-service
ng g class my-new-class
ng g guard my-new-guard
ng g interface my-new-interface
ng g enum my-new-enum
ng g module my-module
npm install --save bootstrap
afterwards, inside angular-cli.json (inside the project’s root folder), find styles and add the bootstrap css file like this:
"styles": [
"../node_modules/bootstrap/dist/css/bootstrap.min.css",
"styles.css"
],
Following is our routing configurtion.We have configured to use LoginComponent as a default component.Also, do not forget to include it in the main module - app.module.ts
app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { DashboardComponent } from './dashboard/dashboard.component';
import { UsercontactComponent } from './usercontact/usercontact.component';
import { AddUsercontactComponent } from './add-usercontact/add-usercontact.component';
import { EditUsercontactComponent } from './edit-usercontact/edit-usercontact.component';
import { AppRoutingModule } from './app.routing.module';
import { ReactiveFormsModule } from '@angular/forms';
@NgModule({
declarations: [
AppComponent,
AddUsercontactComponent,
UsercontactComponent,
DashboardComponent,
EditUsercontactComponent
],
imports: [
BrowserModule,
ReactiveFormsModule,
AppRoutingModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
app.routing.module.ts
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { AddUsercontactComponent } from './add-usercontact/add-usercontact.component';
import { EditUsercontactComponent } from './edit-usercontact/edit-usercontact.component';
import { DashboardComponent } from './dashboard/dashboard.component';
const routes: Routes = [
{ path: 'edit', component: EditUsercontactComponent },
{ path: 'add', component: AddUsercontactComponent },
{ path: '', component: DashboardComponent }
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
Following is the implementation of our UsercontactService
. It has all the API details that is required for the CRUD operation. The UsercontactService
creates a JSON array with dummy user contacts, which can be modified but after restart the data will be reseted.
The CRUD functions: create(), update(), getall(), delete()
and some helper functions: getUserById(), getnextId()
usercontact.service.ts
import { Injectable } from '@angular/core';
import { UserContact } from './usercontact.model';
@Injectable({
providedIn: 'root'
})
export class UsercontactService {
usercontacts: UserContact[] = [{
id: 0,
firstname: 'Alex',
lastname: 'BlaBla',
email: 'alex.blabla@aol.at'
},
{
id: 1,
firstname: 'Otto',
lastname: 'Blubb',
email: 'otto.blubb@dsl.de'
},
{
id: 2,
firstname: 'Peter',
lastname: 'Pan',
email: 'peter.pan@neverland.com'
}];
create(usercontact: UserContact) {
const itemIndex = this.usercontacts.length;
usercontact.id = this.getnextId();
console.log(usercontact);
this.usercontacts[itemIndex] = usercontact;
}
delete(usercontact: UserContact) {
this.usercontacts.splice(this.usercontacts.indexOf(usercontact), 1);
}
update(usercontact: UserContact) {
const itemIndex = this.usercontacts.findIndex(item => item.id === usercontact.id);
console.log(itemIndex);
this.usercontacts[itemIndex] = usercontact;
}
getall(): UserContact[] {
console.log('usercontactservice:getall');
console.log(this.usercontacts);
return this.usercontacts;
}
reorderUserContacts(usercontact: UserContact) {
console.log('Zur Info:', usercontact);
this.usercontacts = this.usercontacts
.map(uc => uc.id === usercontact.id ? usercontact : uc)
.sort((a, uc) => uc.id - uc.id);
}
getUserById(id: number) {
console.log(id);
const itemIndex = this.usercontacts.findIndex(item => item.id === id);
console.log(itemIndex);
return this.usercontacts[itemIndex];
}
getnextId(): number {
let highest = 0;
this.usercontacts.forEach(function (item) {
if (highest === 0) {
highest = item.id;
}
if (highest < item.id) {
highest = item.id;
}
});
return highest + 1;
}
}
After calling the URL the rquest is redirected to the dashboard
and from there the user can perform crud operation.
dashboard.component.html
Contains the button to create a new user contact and the placeholder of usercontact.component
.
If the button create is clicked, the component editUsercontact.component
, because the router calls the path /add
which is defined in the ‘app.routing.module.ts’.
<a [routerLink]="['/add']" class="btn btn-success ml-2">New</a>
<hr>
<app-usercontact></app-usercontact>
usercontact.component.html
Pepares the table, which shows the user contacts from the JSON data.
<div class="usercontact-list">
<table class="table table-bordered">
<thead>
<tr>
<th>Id</th>
<th>Firstname</th>
<th>Lastname</th>
<th>Email</th>
<th>Edit</th>
<th>Delete</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let usercon of usercontacts">
<td></td>
<td></td>
<td></td>
<td></td>
<td>
<button class=" btn btn-primary " (click)="editUserContact(usercon) ">Edit</button>
</td>
<td>
<button class="btn btn-danger ml-2 " (click)="deleteUserContact(usercon) ">Delete</button>
</td>
</tr>
</tbody>
</table>
</div>
usercontact.component.ts
Cotains all the functionality to show the JSON data and to handle all the action triggered by delete and edit.
usercontact.service
with the function getall()edit
which redirects to edit-usercontact.component
usercontact.service
with the function delete()
import { Component, OnInit } from '@angular/core';
import { UserContact } from '../share/usercontact.model';
import { UsercontactService } from '../share/usercontact.service';
import { Router } from '@angular/router';
@Component({
selector: 'app-usercontact',
templateUrl: './usercontact.component.html',
styleUrls: ['./usercontact.component.css'],
})
export class UsercontactComponent implements OnInit {
usercontacts: UserContact[]; // Array<string>
usercont: UserContact;
constructor(private ucs: UsercontactService, private router: Router) {
}
editUserContact(usercontact: UserContact) {
console.log(usercontact);
localStorage.removeItem('editUserId');
localStorage.setItem('editUserId', usercontact.id.toString());
this.router.navigate(['edit']);
// this.ucs.update(usercontact);
}
deleteUserContact(usercontact: UserContact) {
console.log(usercontact);
this.ucs.delete(usercontact);
}
ngOnInit() {
console.log('usercontact:init');
this.usercontacts = this.ucs.getall();
console.log(this.usercontacts);
}
}
add-usercontact.component.html
Shows the formular to create a new user contact. The Validators checking the input of the textfields.
First name and last name will be checked if an input is done.
The validator of Email field checks if an ‘@’ is followed by any word character and a ‘.’ with at least two any word character.
<div class="col-md-6">
<h2 class="text-center">Add User Contact</h2>
<form [formGroup]="addForm" (ngSubmit)="onSubmit()">
<div class="form-group">
<label for="firstname">First Name:</label>
<input formControlName="firstname" placeholder="First Name" name="firstname" class="form-control" id="firstname">
<div class="feedback-red" *ngIf="isInvalid('firstname')">
First Name is empty.
</div>
</div>
<div class="form-group">
<label for="lastname">Last Name:</label>
<input formControlName="lastname" placeholder="Last name" name="lastname" class="form-control" id="lastname">
<div class="feedback-red" *ngIf="isInvalid('lastname')">
Last Name is empty.
</div>
</div>
<div class="form-group">
<label for="email">Email address:</label>
<input type="email" formControlName="email" placeholder="Email" name="email" class="form-control" id="email">
<div class="feedback-red" *ngIf="isEmailInvalid('email')">
Email is not valid.
</div>
</div>
<button button [disabled]="addForm.invalid" class="btn btn-success">Submit</button>
<button class="btn btn-danger ml-2 " (click)="onCancel()">Cancel</button>
</form>
</div>
add-usercontact.component.ts
Contains the functions:
usercontact.service
the function create and calls the router with the root entrie path.
import { Component, OnInit, EventEmitter, Output } from '@angular/core';
import { UserContact } from '../share/usercontact.model';
import { UsercontactService } from '../share/usercontact.service';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { first } from 'rxjs/operators';
import { Router } from '@angular/router';
@Component({
selector: 'app-add-usercontact',
templateUrl: './add-usercontact.component.html',
styleUrls: ['./add-usercontact.component.css']
})
export class AddUsercontactComponent implements OnInit {
constructor(private formBuilder: FormBuilder, private router: Router, private userService: UsercontactService) { }
addForm: FormGroup;
@Output()
createUsercontact = new EventEmitter<UserContact>();
emailRegex = /^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/;
ngOnInit() {
this.addForm = this.formBuilder.group({
id: [],
email: ['', [Validators.required, Validators.pattern(this.emailRegex)]],
firstname: ['', Validators.required],
lastname: ['', Validators.required]
});
}
isInvalid(name: string) {
const control = this.addForm.get(name);
return control.invalid && control.dirty;
}
isEmailInvalid(name: string) {
const control = this.addForm.get(name);
return control.invalid && control.dirty;
}
onSubmit() {
this.userService.create(this.addForm.value);
this.router.navigate(['']);
}
}
edit-usercontact.component.html
Nearly the same as the add-usercontact.component.html
but the text fields contains the values of the selected user contact.
<div class="col-md-6">
<h2 class="text-center">Change User Contact</h2>
<form [formGroup]="addForm" (ngSubmit)="onSubmit()">
<div class="form-group">
<label for="firstname">First Name:</label>
<input formControlName="firstname" placeholder="First Name" name="firstname" class="form-control" id="firstname">
<div class="feedback-red" *ngIf="isInvalid('firstname')">
First Name is empty.
</div>
</div>
<div class="form-group">
<label for="lastname">Last Name:</label>
<input formControlName="lastname" placeholder="Last name" name="lastname" class="form-control" id="lastname">
<div class="feedback-red" *ngIf="isInvalid('lastname')">
Last Name is empty.
</div>
</div>
<div class="form-group">
<label for="email">Email address:</label>
<input type="email" formControlName="email" placeholder="Email" name="email" class="form-control" id="email">
<div class="feedback-red" *ngIf="isEmailInvalid('email')">
Email is not valid.
</div>
</div>
<button button [disabled]="addForm.invalid" class="btn btn-success">Submit</button>
<button class="btn btn-danger ml-2 " (click)="onCancel()">Cancel</button>
</form>
</div>
edit-usercontact.component.ts
import { Component, OnInit, EventEmitter, Output } from '@angular/core';
import { UserContact } from '../share/usercontact.model';
import { UsercontactService } from '../share/usercontact.service';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { first } from 'rxjs/operators';
import { Router } from '@angular/router';
@Component({
selector: 'app-edit-usercontact',
templateUrl: './edit-usercontact.component.html',
styleUrls: ['./edit-usercontact.component.css']
})
export class EditUsercontactComponent implements OnInit {
constructor(private formBuilder: FormBuilder, private router: Router, private userService: UsercontactService) { }
addForm: FormGroup;
usercontact: UserContact;
emailRegex = /^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/;
ngOnInit() {
const userId = localStorage.getItem('editUserId');
if (!userId) {
alert('Invalid action.');
this.router.navigate(['']);
return;
}
this.addForm = this.formBuilder.group({
id: [],
email: ['', [Validators.required, Validators.pattern(this.emailRegex)]],
firstname: ['', Validators.required],
lastname: ['', Validators.required]
});
const data = this.userService.getUserById(+userId);
this.addForm.setValue(data);
}
isInvalid(name: string) {
const control = this.addForm.get(name);
return control.invalid && control.dirty;
}
isEmailInvalid(name: string) {
const control = this.addForm.get(name);
return control.invalid && control.dirty;
}
onSubmit() {
this.userService.update(this.addForm.value);
this.router.navigate(['']);
}
onCancel() {
this.router.navigate(['']);
}
}
Run the command ng serve -o
the browser opens http://localhost:4200
After the browser opened, following screen shows the list of user contacts. On this page, avaiable actions to add, edit and delete user contacts. Following is a sample screen for add user contact.
In this article, we learned about Angular 6 and created a sample example project using it.
The source can be downloaded from github here - Angular6-UserContact-App