HI WELCOME TO Sirees

Angular 8 with Web API – CRUD Operations

Leave a Comment
In this article, we’ll create a CRUD application using Angular 5 with Web API. CRUD Operations Insert Update and Delete will be implemented inside an Asp.net Web API Using Entity Framework and then consumed from an Angular 5 Application.
Application Demo :

Demo Of CRUD Operations In Angular 5 With Web API

Following tools and modules are used for this project :

– Angular CLI
– Angular 8
– ngx-Toastr (npm package)
– Bootstrap and Font-Awesome Icons
– VS Code & Visual Studio Editor

we assume that you have installed required packages and software for angular 8 application development.
Download project source code from GitHub : Angular 8 With Web API – CRUD Operations.

Create SQL Server DB
First of all, let’s create a database to work with. I use Management Studio to create and manage SQL database.

Created a Database with name ‘WebAPIDB’, In this application we’ll deals with details of employees. so an employee table is created using following SQL Script.

Transact-SQL

CREATE TABLE [dbo].[Employee](
[EmployeeID] [int] IDENTITY(1,1) NOT NULL primary key,
[FirstName] [varchar](50) NULL,
[LastName] [varchar](50) NULL,
[EmpCode] [varchar](50) NULL,
[Position] [varchar](50) NULL,
[Office] [varchar](50) NULL)
Here EmployeeID column is the Primary Key and IDENTITY column for the table. Because of IDENTITY specification, we don’t insert values into EmployeeID column. SQL Server will take care of that. It will start from 1 and incremented by 1 upon new record insertion.

Create Web API Application
Database is ready, Now let’s create an Asp.Net Web API project.

Open Visual Studio, Go to File > New > Project (Ctrl + Shift +N).

Create Web API Project

then select Web API template.

Select Web API Project

So here we have created a brand new Web API Project. Now let’s add Entity Model for the DB ‘WEPAPIDB’ inside Models Folder.

Right Click on Models Folder > Add > New Item.

Name your Entity Model as DBModels.edmx.

Create ADO.NET Entity Model For the DB

Select Generate From database.

Select Generate From Database

In Data Connection Window, Click On New Connection.

Configure DB Connection

Provide SQL Server Instance Details and Select the DB.

Provide SQL Server Connection Details and DB Name

As per previous window, we’ll save DB Connection string in WebConfig as DBModel. After creating this Entity Model there will be a class with this name (DBModel), we’ll create an object of this class in-order to interact with database.

After previous window, you may see an extra window as follows, if you have multiple Entity Framework Versions, then select one of them.

Select EF Version

then select tables that we want to add inside the Entity Model.

Select Tables for Entity Model

Click on Finish. Diagrammatic Representation of EF Model looks like this.

Diagrammatic Representation of EF Model

Inside this DBModels.edmx, you can see a DBModels.Context.cs file for DBModel Class. we’ll create an object of this class to work with database.

DBModels.tt > Employee.cs contains Employee Class, which contains properties corresponding to SQL Table Columns, So this is our Model Class.

Now let’s add Employee Controller, before that don’t forget to Re-build your solution. To create a Controller, right click on controllers folder then click on Add > Controller…, Then select Web API 2 Controller with actions, Using Entity Framework Scaffolding Mechanism.then following window will be shown.

Create Web API Controller

It will create Web API Controller Employee using Employee Class from Entity Model. Created controller contains web methods GET,POST,PUT and DELETE for CRUD operations READ INSERT UPDATE AND DELETE respectively. These default web methods contains model validations, we don’t do model validation in this Web API project, Form validation can be done inside angular 8 application, Employee controller without validation looks like this

EmployeeController.csC#

public class EmployeeController : ApiController
{
    private DBModel db = new DBModel();

    // GET api/Employee
    public IQueryable<Employee> GetEmployees()
    {
        return db.Employees;
    }

    // PUT api/Employee/5
    public IHttpActionResult PutEmployee(int id, Employee employee)
    {
        db.Entry(employee).State = EntityState.Modified;
        try
        {
            db.SaveChanges();
        }
        catch (DbUpdateConcurrencyException)
        {
            if (!EmployeeExists(id))
            {
                return NotFound();
            }
            else
            {
                throw;
            }
        }
        return StatusCode(HttpStatusCode.NoContent);
    }

    // POST api/Employee
    [ResponseType(typeof(Employee))]
    public IHttpActionResult PostEmployee(Employee employee)
    {
        db.Employees.Add(employee);
        db.SaveChanges();
        return CreatedAtRoute("DefaultApi", new { id = employee.EmployeeI
    }

    // DELETE api/Employee/5
    [ResponseType(typeof(Employee))]
    public IHttpActionResult DeleteEmployee(int id)
    {
        Employee employee = db.Employees.Find(id);
        if (employee == null)
        {
            return NotFound();
        }
        db.Employees.Remove(employee);
        db.SaveChanges();
        return Ok(employee);
    }

    protected override void Dispose(bool disposing)
    {
        if (disposing)
        {
            db.Dispose();
        }
        base.Dispose(disposing);
    }

    private bool EmployeeExists(int id)
    {
        return db.Employees.Count(e => e.EmployeeID == id) > 0;
    }
}
All these Web API methods are written using DB First Approach in Entity Framework. Now let’s check working of this Web API project, first of all let me add a test employee record inside Employee table.

Transact-SQL

INSERT Employee ( [FirstName], [LastName], [EmpCode], [Position], [Office]) VALUES ('Angelica', 'Ramos', 'AR', 'Angular Developer', 'Texas')
Now let’s run our Web API project. then navigate /api/Employee URL. It will call GetEmployees Method to retrieve employee collection from SQL server table Employee.

View Employee Collection from DB through Web API

Here base URL is localhost:28750, we need this base URL to consume this Web API from Angular 8 Application. Thereby our Web API Project is working fine, finally let me truncate the test record from employee table.

Transact-SQL

truncate table Employee
Create Angular 8 Application
I use Visual Studio Code Editor for Angular Project Development. In-order to create an angular 8 application you can use following Angular CLI command.

ng new AngularCRUD
It will create the application with name AngularCRUD  and install default packages from npm. In-order to run an angular application, you can use following command.

1
ng serve --open
it will open our application from default port number 4200, that means –  http://localhost:4200.

Add Required Angular 8 CRUD Components, Model and Service Class
Now we need to add 3 components. To add an angular component you can do this

//from root component
ng g c employees
Here we creates employees component,remaining two components will be child components for this employees component. following command creates child components employee and employee-list componets.

//switch to parent component directory
cd src\app\employees
//create child components
ng g c employee
ng g c employee-list
Open appmodule.ts file, Make sure that newly added components are added to declarations array.

/src/app/app.module.ts

...
import { EmployeesComponent } from './employees/employees.component';
import { EmployeeComponent } from './employees/employee/employee.component';
import { EmployeeListComponent } from './employees/employee-list/employee-list.component';
@NgModule({
    ....
    declarations: [
    ...
    EmployeesComponent,
    EmployeeComponent,
    EmployeeListComponent
    ],
    ...
Let’s Start the Design
We’ll use Bootstrap and Font-Awesome Icons For Application Design. So first of all add CDN reference for these style sheets inside index.html .

/src/index.html

<!-- Bootstrap -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css" integrity="sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M" crossorigin="anonymous">
<!-- font-awesome -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
Update app.component.html as follows

/src/app/app.component.html

<div class="container">
  <app-employees></app-employees>
</div>
Add Following to employees.component.html file.

/src/app/employees/employees.component.html

<div style="text-align:center">
  <h2 class="jumbotron bg-secondary text-white">Employee Register</h2>
</div>
<div class="row">
  <div class="col-md-6">
    <app-employee></app-employee>
  </div>
  <div class="col-md-6">
    <app-employee-list></app-employee-list>
  </div>
</div>
We need Model and Services to design remaining child components.

Create Service and Model Classes
To create these classes let’s add a new folder shared, inside employees folder (/src/app/employees/ ).

Now create employee model class

//switch to shared folder
cd src\app\employees\shared
//create employee model class
ng g class employee --type=model
//create employee service class
ng g s employee
in this application we deals with employee details like

First Name
Last Name
Emp Code
Position
Office Location
So we have to add properties corresponding to these employee’s details inside employee.model.ts file.

/src/app/employees/shared/employee.model.ts

export class Employee {
    EmployeeID : number;
    FirstName:string;
    LastName:string;
    EmpCode:string;
    Position:string;
    Office:string;
}
EmployeeID property is used to identify each employee record individually inside the application.

Inside Employee service class,we defined functions for each CRUD operation in Angular 8 with Web API.That means we consume Web API methods from this service class.

/src/app/employees/shared/employee.service.ts

import { Injectable } from '@angular/core';
import { Http, Response, Headers, RequestOptions, RequestMethod } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/toPromise';

import {Employee} from'./employee.model'

@Injectable()
export class EmployeeService {
  selectedEmployee : Employee;
  employeeList : Employee[];
  constructor(private http : Http) { }

  postEmployee(emp : Employee){
    var body = JSON.stringify(emp);
    var headerOptions = new Headers({'Content-Type':'application/json'});
    var requestOptions = new RequestOptions({method : RequestMethod.Post,headers : headerOptions});
    return this.http.post('http://localhost:28750/api/Employee',body,requestOptions).map(x => x.json());
  }

  putEmployee(id, emp) {
    var body = JSON.stringify(emp);
    var headerOptions = new Headers({ 'Content-Type': 'application/json' });
    var requestOptions = new RequestOptions({ method: RequestMethod.Put, headers: headerOptions });
    return this.http.put('http://localhost:28750/api/Employee/' + id,
      body,
      requestOptions).map(res => res.json());
  }

  getEmployeeList(){
    this.http.get('http://localhost:28750/api/Employee')
    .map((data : Response) =>{
      return data.json() as Employee[];
    }).toPromise().then(x => {
      this.employeeList = x;
    })
  }

  deleteEmployee(id: number) {
    return this.http.delete('http://localhost:28750/api/Employee/' + id).map(res => res.json());
  }
}
In this service class we have imported http and rxjs related classes. http class is used to consume the Web API methods for Insert Update and Delete operations.

But there is a Problem – CORS
CORS (Cross-Origin Resource Sharing) : it is a mechanism to let a user agent (browser) gain permission to access selected resources from a server on a different origin (domain) than the site currently in use. cross-origin HTTP request occurs when it requests a resource from a different domain, protocol, or port than the one from which the current document originated.

In this application, our web API project will block request from angular 8 application, since they are cross-origin HTTP request(from different port numbers – 4200 and 28750). In-order to allow cross-origin HTTP request, we have to configure Web API project for this localhost:4200 request. so let’s look how we can do that.

First of we have to install NuGet Package : WebApi.Cors. Back to Visual Studio, Select your Web API project from solution explorer, then go to Tools > Library Package Manager > Package Manager Console. use following NuGet command to install WebApi.Cors.

Install-Package Microsoft.AspNet.WebApi.Cors -Version 5.2.3
NuGet Command for Web API Cors

Now let’s look how we can use this package. In-order allow cross-origin request in Web API controller Employee we can do this.

...
using System.Web.Http.Cors;

[EnableCors(origins: "http://localhost:4200", headers: "*", methods: "*")]
public class EmployeeController : ApiController
{
   .....
}
Here we have given permission for http request from ‘http://localhost:4200’, it’s not a good idea to add this EnableCors attribute for all Web API controlls if your project is big in size. In that case you do this.

Go to App_Start >WebApiConfig.cs file. add following lines of code

/App_Start/WebApiConfig.csC#

...
using System.Web.Http.Cors;

public static class WebApiConfig
{
   public static void Register(HttpConfiguration config)
   {
       config.EnableCors(new EnableCorsAttribute("http://localhost:4200", headers: "*", methods: "*"));
       ...
now web API project is ready for cross-origin request from our angular 8 application.

try to navigate this URL /api/Employee from your web API project some of you may get this problem.

Could not load file or assembly System.Web.Http

It is due to different version of WebApi.Cors (5.2.3) and System.Web.Http (5.0.0), so lets install same version of WebApi.Core (Not Cors it is Core). it will resolve this assembly problem. for that you can run following NuGet Command from Package Manager Console.

1
Install-Package Microsoft.AspNet.WebApi.Core -Version 5.2.3
So here we have completed with Web APi Project. Back to angular 8 project.

Angular 8 Project Structure

● src
+---● app
|   +--● employees
|   |  |--employees.component.ts|.html|.css
|   |  +--● employee (employee form)
|   |  |  |--employee.component.ts|.html|.css
|   |  |
|   |  +--● employee-list (list inserted employees)
|   |  |  |--employee-list.component.ts|.html|.css
|   |  |
|   |  +--● shared
|   |     |--employee.service.ts
|   |     |--employee.model.ts
|   |
|   |--app.module.ts (configured firebase connection)
|
+---● environments
|   |--environment.ts
|
|--index.html (cdn path for bootstrap and font awesome icon)
This our application structure, component employees will be the parent component for employee and employee-list component.
We are going to inject EmployeeService inside the Parent Component Employees. and there by we can access the same injected service instance from child components Employee and Employee-List. so whenever we make make changes in one child component same change can seen from other child component also.

Inject Employee Service in Components :
first of all inject the service class inside parent component Employees

/src/employees/employees.component.ts

...
import { EmployeeService } from './shared/employee.service'
@Component({
  ...
  providers :[EmployeeService]
})
export class EmployeesComponent implements OnInit {
  constructor(private employeeService : EmployeeService) { }
  ...
}
To inject a class inside a component , mention the class inside component providers array and then create private parameter inside component constructor.

Now we can use this injected instance in child components, Inside employee.component.ts file

/src/app/employee/employee.component.ts

...
import { EmployeeService } from '../shared/employee.service';
@Component({
  ...
})
export class EmployeeComponent implements OnInit {
    constructor(private employeeService: EmployeeService){
    }
...
}
And inside employee-list.component.ts file

/src/app/employee/employee-list.component.ts

...
import { EmployeeService } from '../shared/employee.service';
@Component({
  ...
})
export class EmployeeListComponent implements OnInit {
    constructor(private employeeService: EmployeeService){
    }
...
}
Angular 8 CRUD Operations Form
we’ll create an employee form to implement Insert and Update Operation with employee Component. So we are going to create a Template Driven Form(TDF) using selectedEmployee property from injected EmployeeService Class.

So first of all we have to import FormsModule and HttpModule  in appmodule.ts file.

/src/app/app.module.ts

...
import { FormsModule} from '@angular/forms';
import { HttpModule } from '@angular/http';
...
@NgModule({
...
imports: [
         ...
         FormsModule,
         HttpModule
         ],
...
So you can use following html in employee.component.html file.

/src/app/employees/employee/employee.component.html

<form class="emp-form" #employeeForm="ngForm" (ngSubmit)="onSubmit(employeeForm)">
  <input type="hidden" name="EmployeeID" #EmployeeID="ngModel" [(ngModel)]="employeeService.selectedEmployee.EmployeeID">
  <div class="form-row">
    <div class="form-group col-md-6">
      <input class="form-control" name="FirstName" #FirstName="ngModel" [(ngModel)]="employeeService.selectedEmployee.FirstName"
        placeholder="First Name" required>
      <div class="validation-error" *ngIf="FirstName.invalid && FirstName.touched">This Field is Required.</div>
    </div>
    <div class="form-group col-md-6">
      <input class="form-control" name="LastName" #LastName="ngModel" [(ngModel)]="employeeService.selectedEmployee.LastName" placeholder="Last Name"
        required>
      <div class="validation-error" *ngIf="LastName.invalid && LastName.touched">This Field is Required.</div>
    </div>
  </div>
  <div class="form-group">
    <input class="form-control" name="Position" #Position="ngModel" [(ngModel)]="employeeService.selectedEmployee.Position" placeholder="Position">
  </div>
  <div class="form-row">
    <div class="form-group col-md-6">
      <input class="form-control" name="EmpCode" #EmpCode="ngModel" [(ngModel)]="employeeService.selectedEmployee.EmpCode" placeholder="Emp Code">
    </div>
    <div class="form-group col-md-6">
      <input class="form-control" name="Office" #Office="ngModel" [(ngModel)]="employeeService.selectedEmployee.Office" placeholder="Office">
    </div>
  </div>
  <div class="form-row">
    <div class="form-group col-md-8">
      <button [disabled]="!employeeForm.valid" type="submit" class="btn btn-lg btn-block btn-info">
        <i class="fa fa-floppy-o"></i> Submit</button>
    </div>
    <div class="form-group col-md-4">
      <button type="button" class="btn btn-lg btn-block btn-secondary" (click)="resetForm(employeeForm)">
        <i class="fa fa-repeat"></i> Reset</button>
    </div>
  </div>
</form>
and this employee form will look like this.

Screen shot Employee Form

This form design is inspired from Bootstrap Custom Form Styles. A hidden field is added for EmployeeID property.

Form Validation
required attribute is added to First Name and Last Name text boxes, so these two fields are mandatory to submit this form.When these text-boxes are invalid,  ng-invalid and ng-dirty class will automatically added to it. so based on these classes we have implemented form validation.

when these text boxes are not valid, employee form as whole is not valid, so we added conditional disable attribute to Submit Button.


<button
[disabled]="!employeeForm.valid"
type="submit" class="btn btn-lg btn-block btn-info">
        <i class="fa fa-floppy-o"></i> Submit</button>
to show validation error, we’ll show red border around these text box using CSS. complete css rules for this application to global css file styles.css.

/src/styles.cssCSS

form.emp-form{
    background-color: #dbdbdb;
    border-radius: 4px;
    padding: 10px;
}
div.validation-error{
    color: red;
    text-align: center;
}
button:hover,a.btn:hover{
    cursor: pointer;
}

Insert,Update  and Reset Operation
Inside employee.component.ts file we’ll write code for Insert, Update and Delete Operation. Before that I’m going to install ngx-toastr from npm package. this package helps us to show notification message inside angular applications.

 ngx-toastr package installation
In-order to install the package, you can use following npm command.

1
npm install ngx-toastr --save
then add ToastrModule inside appmodule.ts file.

...
import { ToastrModule } from 'ngx-toastr';
@NgModule({
   ...
   imports: [
   ...
   ToastrModule.forRoot()
   ],
...
Then add toastr.css style-sheet reference in .angular-cli.json file.

...
"styles": [
        "styles.css",
        "../node_modules/ngx-toastr/toastr.css"
      ],
...
Now you can add following code inside employee component typescript file.

/src/app/employees/employee/employee.component.ts

import { Component, OnInit } from '@angular/core';
import { NgForm } from '@angular/forms'

import { EmployeeService } from '../shared/employee.service'
import { ToastrService } from 'ngx-toastr'
@Component({
  selector: 'app-employee',
  templateUrl: './employee.component.html',
  styleUrls: ['./employee.component.css']
})
export class EmployeeComponent implements OnInit {

  constructor(private employeeService: EmployeeService, private toastr: ToastrService) { }

  ngOnInit() {
    this.resetForm();
  }

  resetForm(form?: NgForm) {
    if (form != null)
      form.reset();
    this.employeeService.selectedEmployee = {
      EmployeeID: null,
      FirstName: '',
      LastName: '',
      EmpCode: '',
      Position: '',
      Office: ''
    }
  }

  onSubmit(form: NgForm) {
    if (form.value.EmployeeID == null) {
      this.employeeService.postEmployee(form.value)
        .subscribe(data => {
          this.resetForm(form);
          this.employeeService.getEmployeeList();
          this.toastr.success('New Record Added Succcessfully', 'Employee Register');
        })
    }
    else {
      this.employeeService.putEmployee(form.value.EmployeeID, form.value)
      .subscribe(data => {
        this.resetForm(form);
        this.employeeService.getEmployeeList();
        this.toastr.info('Record Updated Successfully!', 'Employee Register');
      });
    }
  }
}
restForm function is used reset form controls value to initial stage, we called this function from reset button click event and from ngOnint  Lifecycle Hook to initialise the form.

Inside the form submit event function OnSubmit, we implement both insert and update operation based on EmployeeID value. To show the success message,  we use ToastrService class object toastr.

List Inserted Records and Delete Operation
Using employee-list component we’ll list all inserted employees and implement Delete operation.

you can add following inside employee-list component.

/src/app/employees/employee-list/employee-list.component.ts

import { Component, OnInit } from '@angular/core';

import { EmployeeService } from '../shared/employee.service'
import { Employee } from '../shared/employee.model';
import { ToastrService } from 'ngx-toastr'; 
@Component({
  selector: 'app-employee-list',
  templateUrl: './employee-list.component.html',
  styleUrls: ['./employee-list.component.css']
})
export class EmployeeListComponent implements OnInit {

  constructor(private employeeService: EmployeeService,private toastr : ToastrService) { }

  ngOnInit() {
    this.employeeService.getEmployeeList();
  }

  showForEdit(emp: Employee) {
    this.employeeService.selectedEmployee = Object.assign({}, emp);;
  }


  onDelete(id: number) {
    if (confirm('Are you sure to delete this record ?') == true) {
      this.employeeService.deleteEmployee(id)
      .subscribe(x => {
        this.employeeService.getEmployeeList();
        this.toastr.warning("Deleted Successfully","Employee Register");
      })
    }
  }
}
Inside this we have injected EmployeeService and ToastrService Class. Inside the ngOnint  Lifecycle Hook, we called getEmployeeList from EmployeeService class. It will store employee collection from Employee table inside employeeList array. Now we can use this array to list employee collection. You can add following html code inside employee-list.component.html file.

/src/app/employees/employee-list/employee-list.component.html

<table class="table table-sm table-hover">
  <tr *ngFor="let employee of employeeService.employeeList">
    <td>{{employee.FirstName}} - {{employee.LastName}}</td>
    <td>{{employee.EmpCode}}</td>
    <td>
      <a class="btn" (click)="showForEdit(employee)">
        <i class="fa fa-pencil-square-o"></i>
      </a>
      <a class="btn text-danger" (click)="onDelete(employee.EmployeeID)">
        <i class="fa fa-trash-o"></i>
      </a>
    </td>
  </tr>
</table>
Component design looks like this

employee-list component design

when we click on pencil button it will call showForEdit function to populate corresponding record inside the employee form.Using trash icon we implemented delete operation with onDelete  function.

Download project source code from GitHub : Angular 8 With Web API – CRUD Operations.

0 comments:

Post a Comment

Note: only a member of this blog may post a comment.