Wednesday 10 June 2020

Angular CRUD(Reactive Form) example with database

Click to setup Angular environment

Click to Create simple Web API with ASP.NET

This demo is based on Reactive Form (RF). In this we will perform a simple CRUD operation with database using ASP.Net Web API.

Key Features Point: -

1. Student Component

2. Student List Component

3. Student Service

4. Student Class

To Do: -

1. Attach Student & Student List selector in the app.component.html.

2. Import StudentService in the app.module.ts.

3. Import ReactiveFormsModule in the app.module.ts.

4. Import BrowserAnimationsModule in the app.module.ts.

5. Import HttpClientModule in the app.module.ts.

6. Show messages alert, install the ngx-toastr service.

7. After installing ngx-toastr service, Import ToastrModule in the app.module.ts.

8. Register toastr.css in the angular.json, inside the styles attributes.

9. Use to bootstrap features, register the bootstrap CDN in the index.html.


Lets Start the Project


Step 1: - Create “AngularDemo” folder in the D drive

Step 2: - Open Visual Studio Code

Step 3: - Go to File => Click on Open Folder… => Browse and select created folder “AngularDemo” in the D drive

Step 4: - Type ng new AngularCRUDWithDB => Press Enter 


Step 5: - ? Would you like to add Angular routing? (y/N) => Type => Press Enter


Step 6: - ? Which stylesheet format would you like to use? (Use arrow keys) => Select CSS => Press Enter



Note: - Project created

Step 7: - Go to File => Click on Open Folder… => Browse and select created Project AngularCRUDWithDB from path D:\AngularDemo\AngularCRUDWithDB 


Step 8: -Project Loaded in Visual Studio Code


Step 9: - Open Terminal => Go to Terminal => Click on New Terminal



Install “ngx-toaster” package

URL: -https://www.npmjs.com/package/ngx-toastr

Step 10: - Type npm install ngx-toastr --save => Press Enter



Step 11: - Type npm install @angular/animations –-save => Press Enter

Note: -

In latest version angular @angular/animations is default installed, in that case no need to do this step. For verifying the same open package.json file and check dependencies tag.


Step 12: - Open angular.json file and add "node_modules/ngx-toastr/toastr.css" in the styles tag


Step 13: - Open app.module.ts file => Import ToastrModule and BrowserAnimationsModule

import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { ToastrModule } from 'ngx-toastr';


Note: -

  1. ngx-toastr setup done. In upcoming step, we use the ngx-toastr. 
  2. In this demo, we are using the reactive form. For that import ReactiveFormsModule in app.module.ts file.
import { ReactiveFormsModule from '@angular/forms';


Step 14: - Add Student component => Type ng g c Student => Press Enter


Step 15: - Add StudentList component => Type ng g c StudentList => Press Enter


Step 16: - Add Student service => Type ng g s Student => Press Enter


Step 17: - Add Student class => Type ng g cl Student => Press Enter


Step 18: - Open student.ts file => Copy Past following in student.ts file

export class Student {
    public Id : number;
    public Name : string;
    public DOB : Date;
    public Gender : string;
}


Step 19: - Open student.service.ts file => Copy Past following in student.service.ts file

Note:- Import HttpClient to call the Web Api.

import { Injectable } from "@angular/core";
import { Student } from "./student";
import { FormGroup } from "@angular/forms";
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';

@Injectable()
export class StudentService {
  //To Bind Student form data
  public studentFormFormGroup;
  //To Fill Gender Dropdown
  public genders = ["Male""Female""Other"];
  //To Store/Get/Delete data from array
  public studentList = [];

  //Base URL
  public URL :  any = "http://localhost:7085/api/Students";

  constructor(private http : HttpClient) {}

  Insert(studentStudent) : Observable<any> {
    return this.http.post(this.URLstudent);
  }

  Update(studentStudent) : Observable<any> {
    return this.http.put(this.URL + "/"student.Id +""student);
  }

  Get() {
    return this.http.get(this.URL).subscribe((response: {}) => {
      this.studentList = response as Student[]});
  }

  Delete(idnumber) : Observable<any> {
    return this.http.delete(this.URL + "/" + id);
  }
}

Step 20: - Open app.component.ts file => Copy Past following in app.component.ts file

import { ComponentVERSION } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  name = 'CRUD Reactive Form-Angular ' + VERSION.major;
}

Step 21: - Open app.component.html file => Clear default code => Copy Past following in app.component.html file

<div class="container">
  <h1>Hello {{title}}!</h1>
</div>
<app-student></app-student>
<hr>
<app-student-list></app-student-list>

Step 22: - Open student.component.ts file => Copy Past following in student.component.ts file

import { ComponentOnInit } from "@angular/core";
import { StudentService } from "../student.service";
import { FormGroupFormBuilderValidators } from "@angular/forms";
import { ToastrService } from "ngx-toastr";
import { Student } from "../student";
import { HttpErrorResponse } from '@angular/common/http';

@Component({
  selector: "app-student",
  templateUrl: "./student.component.html",
  styleUrls: ["./student.component.css"]
})
export class StudentComponent implements OnInit {
  //This property used for reset the form
  public studentStudent = {
    Id: null,
    Name: "",
    DOB: null,
    Gender: ""
  };

  constructor(
    public serviceStudentService,
    private toastToastrService,
    private formBuilderFormBuilder
  ) {}

  ngOnInit() {
    this.ResetForm();
  }

  // get formControls() { return this.studentForm.controls; }
  get name() {
    return this.service.studentForm.get("Name");
  }
  get dob() {
    return this.service.studentForm.get("DOB");
  }
  get gender() {
    return this.service.studentForm.get("Gender");
  }

  ResetForm(studentForm?: FormGroup) {
    if (this.service.studentForm != null) {
      this.service.studentForm.reset(this.student);
    }
    this.service.studentForm = this.formBuilder.group({
      Id: [null],
      Name: ["", [Validators.requiredValidators.minLength(3)]],
      DOB: [""Validators.required],
      Gender: [""Validators.required]
    });
  }

  submitForm() {
    if (this.service.studentForm.value.Id == null) {
      this.InsertForm(this.service.studentForm.value);
    } else {
      this.updateForm(this.service.studentForm.value);
    }
  }

  InsertForm(studentStudent) {
    this.service.Insert(student).subscribe(response =>{
      this.toast.success("Inserted Successfully.""Success!");
      this.service.Get();
      this.ResetForm();
    },
    (error : HttpErrorResponse=> {
      console.log(error);
    });
  }

  updateForm(studentStudent) {
    this.service.Update(student).subscribe(response =>{
      this.toast.info("Updated Successfully.""Success!");
      this.service.Get();
      this.ResetForm();
    },
    (error : HttpErrorResponse=> {
      console.log(error);
    });
  }
}

Step 23: - Open student.component.html file => Copy Past following in student.component.html file

<div class="container">
    <form [formGroup]="service.studentForm" (ngSubmit)="submitForm()">
        <input type="hidden" formControlName="Id">
        <div class="form-group">
            <input formControlName="Name" class="form-control" placeholder="Enter Name">
            <div *ngIf="name.invalid && name.touched" class="validation-error">
                <div *ngIf="name.errors?.required">Name is required.</div>
                <div *ngIf="name.errors?.minlength">Name must be at least 3 characters long.</div>
            </div>
        </div>
        <div class="form-group">
            <input type="date" formControlName="DOB" class="form-control" placeholder="Enter DOB">
            <div *ngIf="dob.invalid && dob.touched" class="validation-error">DOB is required.</div>
        </div>
        <div class="form-group">
            <select formControlName="Gender" class="form-control">
          <option value=''>Select Gender</option>
            <option *ngFor="let gender of service.genders" [value]="gender">
              {{gender}}
            </option>
      </select>
            <div *ngIf="gender.invalid && gender.touched" class="validation-error">Gender is required</div>
        </div>
        <div class="form-group">
            <input type="submit" class="btn btn-primary btn-lg btn-block" [disabled]="!service.studentForm.valid"></div>
    </form>
</div>

Step 24: - Open student-list.component.ts file => Copy Past following in student-list.component.ts file

import { ComponentOnInit } from "@angular/core";
import { StudentService } from "../student.service";
import { Student } from "../student";
import { ToastrService } from "ngx-toastr";
import { formatDate } from '@angular/common';
import { HttpErrorResponse } from '@angular/common/http';

@Component({
  selector: "app-student-list",
  templateUrl: "./student-list.component.html",
  styleUrls: ["./student-list.component.css"]
})
export class StudentListComponent implements OnInit {

  constructor(public serviceStudentServicepublic toastToastrService) {}

  ngOnInit() {
    this.GetStudentList();
  }

  GetStudentList() {
    this.service.Get();
  }

  EditForm(studentStudent) {
    this.service.studentForm.setValue({
      Id: student.Id,
      Name: student.Name,
      DOB: formatDate(student.DOB'yyyy-MM-dd''en-US'),
      Gender: student.Gender
    });
  }

  DeleteRecord(idnumber) {
    if (confirm("Are you sure to delete.")) {
      this.service.Delete(id).subscribe(response => {
        this.toast.warning("Deleted Successfully.""Success!");
        this.GetStudentList();
      },
      (error : HttpErrorResponse=> {
        console.log(error);
      });
    }
  }
}

Step 25: - Open student-list.component.html file => Copy Past following in student-list.component.html file

<div class="container" *ngIf="service.studentList.length">
    <table class="table table-bordered">
        <thead class="thead-dark">
            <tr>
                <th scope="col">SrNo</th>
                <th scope="col">Name</th>
                <th scope="col">DOB</th>
                <th scope="col">Gender</th>
                <th scope="col" class="text-center" colspan="2">Action</th>
            </tr>
        </thead>
        <tbody>
            <tr scope="row" *ngFor="let student of service.studentList;let indx = index">
                <td>{{indx+1}}</td>
                <td>{{student.Name}}</td>
                <td>{{student.DOB | date : "yyyy-MM-dd" }}</td>
                <td>{{student.Gender}}</td>
                <td class="text-center">
                    <button (click)="EditForm(student)" class="btn btn-sm btn-outline-info">Edit</button></td>
                <td class="text-center">
                    <button (click)="DeleteRecord(student.Id)" class="btn btn-sm btn-outline-danger">Delete</button></td>
            </tr>
        </tbody>
    </table>
</div>

Step 26: - Open Root styles.css file => Copy Past following in Root styles.css file

/* You can add global styles to this file, and also import other style files */
input.ng-touched.ng-invalid {
    border-color:red;
}
.validation-error {
    color : red;
}

Step 27: - Open app.module.ts file and import StudentService, HttpClientModule and register the StudentService in Providers tag

import { StudentService from './student.service';
import { HttpClientModule }    from '@angular/common/http';

@NgModule({
  declarations: [
  ],
  imports: [
    HttpClientModule
  ],
  providers: [StudentService],
  bootstrap: [AppComponent]
})
export class AppModule { }

Step 28: - To use bootstrap => Open index.html file and add bootstrap CDN link in html head tag.

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>AngularCRUDWithDB</title>
  <base href="/">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" type="image/x-icon" href="favicon.ico">
  <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
</head>
<body>
  <app-root></app-root>
</body>
</html>

Step 29: - Open Terminal => Type ng serve --o => Press Enter

Add Done

Output


Note:-

When you post the data to web api, where model state checking in Post Student function generate an error. Because of the Id property data type is integer and it could not be null and we are not passing the same while saving the data.
Time being comment the ModelState checking in web api and test your application.

//POST: api/Students
[ResponseType(typeof(Student))]
public IHttpActionResult PostStudent(Student student)
{
    //if(!ModelState.IsValid)
    //{
    //    return BadRequest(ModelState);
   
//}
 
    db.Students.Add(student);
    db.SaveChanges();
 
    return CreatedAtRoute("DefaultApi", new { id = student.Id }, student);
}