employee.ts (parent)
export interface IEmployee {
id: number;
code: string;
name: string;
salary: number;
starRating: number;
}
employee.service.ts
import { HttpErrorResponse } from '@angular/common/http';
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable, throwError } from 'rxjs';
import { catchError, tap } from 'rxjs/operators';
import { IEmployee } from './employee';
@Injectable({
providedIn: 'root'
})
export class EmployeeService {
constructor(private http: HttpClient) {}
getEmployees(): Observable<IEmployee[]> {
return this.http
.get<IEmployee[]>('https://609e2e9f33eed80017957f8d.mockapi.io/employee')
.pipe(
tap(data => console.log('All', JSON.stringify(data))),
catchError(this.handleError)
);
}
private handleError(err: HttpErrorResponse) {
let errorMessage = '';
if (err.error instanceof ErrorEvent) {
errorMessage = `An Error Occured:${err.error.message}`;
} else {
errorMessage = `Server returned code:${err.status}, error message is:${
err.message
}`;
}
console.log(errorMessage);
return throwError(errorMessage);
}
}
employee-component.component.ts (parent)
import { Component, OnDestroy, OnInit } from '@angular/core';
import { Subscription } from 'rxjs';
import { IEmployee } from './employee';
import { EmployeeService } from './employee.service';
@Component({
selector: 'app-employee-component',
templateUrl: './employee-component.component.html',
styleUrls: ['./employee-component.component.css']
})
export class EmployeeComponentComponent implements OnInit, OnDestroy {
sub!: Subscription;
private _listFilter: string = '';
private errorMessage: string = '';
filteredEmployees: IEmployee[] = [];
employees: IEmployee[] = [];
constructor(private employeeService: EmployeeService) {}
//ALTERNATIVE CODE OF CONSTRUCTOR
// private employeeService;
// constructor(employeeService: EmployeeService) {
// this.employeeService = employeeService;
// }
ngOnInit() {
this.sub = this.employeeService.getEmployees().subscribe({
next: employees => {
this.employees = employees;
this.filteredEmployees = this.employees;
},
error: err => (this.errorMessage = err)
});
}
get listFilter(): string {
return this._listFilter;
}
set listFilter(value: string) {
this._listFilter = value;
console.log('In Setter:', value);
this.filteredEmployees = this.performFilter(value);
}
performFilter(filterBy: string): IEmployee[] {
filterBy = filterBy.toLocaleLowerCase();
return this.employees.filter((employee: IEmployee) =>
employee.name.toLocaleLowerCase().includes(filterBy)
);
}
ngOnDestroy() {
this.sub.unsubscribe();
}
}
employee-component.component.html (parent)
<div>
<div>
<input type="text" [(ngModel)]="listFilter" />
</div>
<br />
<div>
Filter By: {{listFilter}}
</div>
<div>
<table>
<thead>
<td>Id</td>
<td>Code</td>
<td>Name</td>
<td>Salary</td>
<td>Rating</td>
</thead>
<tr *ngFor="let employee of filteredEmployees">
<td>{{employee.id}}</td>
<td>{{employee.code}}</td>
<td>
<a [routerLink]="['/employees',employee.id]">
{{employee.name}}
</a>
</td>
<td>{{employee.salary}}</td>
<td>
<app-star [rating]="employee.starRating"></app-star>
</td>
</tr>
</table>
</div>
</div>
star.component.ts (child)
import { Component, Input, OnChanges, OnInit } from '@angular/core';
@Component({
selector: 'app-star',
templateUrl: './star.component.html',
styleUrls: ['./star.component.css']
})
export class StarComponent implements OnChanges {
constructor() {}
@Input() rating: number = 0;
cropWidth: number = 75;
ngOnChanges(): void {
this.cropWidth = this.rating * (75 / 5);
}
}
star.component.html (child)
<div class="crop" [style.width.px]="cropWidth" title="rating">
<div style="width:75px">
<span class="fa fa-star"></span>
<span class="fa fa-star"></span>
<span class="fa fa-star"></span>
<span class="fa fa-star"></span>
<span class="fa fa-star"></span>
</div>
</div>
star.component.css (child)
.crop {
overflow: hidden;
}
div {
cursor: pointer;
}
employeedetail-component.component.ts
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
@Component({
templateUrl: './employeedetail-component.component.html',
styleUrls: ['./employeedetail-component.component.css']
})
export class EmployeedetailComponentComponent implements OnInit {
pageTitle: string = 'Employee Detail';
constructor(private route: ActivatedRoute, private router: Router) {}
ngOnInit() {
const id = Number(this.route.snapshot.paramMap.get('id'));
this.pageTitle += `: ${id}`;
}
onBack(): void {
this.router.navigate(['/employees']);
}
}
employeedetail-component.component.html
<div class="card">
<div class="card-header">
{{pageTitle}}
</div>
<div class="card-footer">
<button class="btn btn-outline-secondary" (click)='onBack()'>
<i class="fa fa-chevron-left"></i>Back
</button>
</div>
</div>
employeedetails.guard.ts
import { Injectable } from '@angular/core';
import {
CanActivate,
ActivatedRouteSnapshot,
RouterStateSnapshot,
Router
} from '@angular/router';
import { Observable } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class EmployeedetailGuard implements CanActivate {
constructor(private router: Router) {}
canActivate(
next: ActivatedRouteSnapshot,
state: RouterStateSnapshot
): Observable<boolean> | Promise<boolean> | boolean {
const id = Number(next.paramMap.get('id'));
if (isNaN(id) || id < 1) {
alert('Invlaid Employee Id');
this.router.navigate(['/employees']);
return false;
}
return true;
}
}
welcome-component.component.ts
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-welcome-component',
templateUrl: './welcome-component.component.html',
styleUrls: ['./welcome-component.component.css']
})
export class WelcomeComponentComponent implements OnInit {
constructor() { }
ngOnInit() {
}
}
welcome-component.component.html
<div>
Welcome Works!
</div>
employee.module.ts
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { RouterModule } from '@angular/router';
import { EmployeeComponentComponent } from './employee-component.component';
import { StarComponent } from '../shared/star/star.component';
import { EmployeedetailComponentComponent } from './employeedetail-component/employeedetail-component.component';
import { EmployeedetailGuard } from './employeedetail-component/employeedetail.guard';
@NgModule({
imports: [
CommonModule,
FormsModule,
RouterModule.forChild([
{ path: 'employees', component: EmployeeComponentComponent },
{
path: 'employees/:id',
component: EmployeedetailComponentComponent,
canActivate: [EmployeedetailGuard]
}
])
],
declarations: [
EmployeeComponentComponent,
StarComponent,
EmployeedetailComponentComponent
]
})
export class EmployeeModule {}
style.css
Install bootstrap font-awesome and import in style.css
@import '~bootstrap/dist/css/bootstrap.min.css';
@import 'font-awesome/css/font-awesome.min.css';
app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { HttpClientModule } from '@angular/common/http';
import { RouterModule } from '@angular/router';
import { WelcomeComponentComponent } from './welcome-component/welcome-component.component';
import { EmployeeModule } from './employee-component/employee.module';
@NgModule({
imports: [
BrowserModule,
HttpClientModule,
RouterModule.forRoot([
{ path: 'welcome', component: WelcomeComponentComponent },
{ path: '', redirectTo: 'welcome', pathMatch: 'full' },
{ path: '**', redirectTo: 'welcome', pathMatch: 'full' }
]),
EmployeeModule
],
declarations: [AppComponent],
bootstrap: [AppComponent]
})
export class AppModule {}
app.component.html
<nav class='navbar navbar-expand navbar-light bg-light'>
<a class='navbar-brand'>{{pageTitle}}</a>
<ul class='nav nav-pills'>
<li>
<a class='nav-link' [routerLink]="['/welcome']">Home</a>
<li>
<li>
<a class='nav-link' [routerLink]="['/employees']">Employee List</a>
<li>
<!-- <li>
<a routerLink="/welcome">Home</a>
<li>
<li>
<a routerLink="/employees">Employee List</a>
<li> -->
</ul>
</nav>
<div class='container'>
<router-outlet></router-outlet>
</div>