Ví dụ về CRUD cho Angular 10 ( Frontend ) cho các bạn mới bắt đầu

19th Aug 2021
Table of contents

Ví dụ dưới đây rất cơ bản để bắt đầu học về Angular 10 trở lên. Chúc các bạn theo nghề lập trình hạnh phúc.

Install Angular 10

npm install -g @angular/cli@10

ng version

1 – Create app

ng new app-tutofox

Would you like to add Angular routing? (y/N): y

2 – Install bootstrap

ng add @ng-bootstrap/ng-bootstrap

3 – Create module

ng generate module person --routing

4 – Create component

ng generate component person/index
ng generate component person/create
ng generate component person/edit

5 – Create routes

src/app/person/person-routing.module.ts

import { IndexComponent } from './index/index.component';

import { CreateComponent } from './create/create.component';

import { EditComponent } from './edit/edit.component';  

const routes: Routes = [

  { path: 'person', redirectTo: 'person/index', pathMatch: 'full'},

  { path: 'person/index', component: IndexComponent },

  { path: 'person/create', component: CreateComponent },

  { path: 'person/edit/:idPerson', component: EditComponent } 

];

6 – Create interface

ng generate interface person/person

src/app/person/person.ts

export interface Person {

    id: number;

    name: string;

    email: string;

    phone: number;

}​

7 – Create services

ng generate service person/person

src/app/person/person.service.ts

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

import { HttpClient, HttpHeaders } from '@angular/common/http';​

import {  Observable, throwError } from 'rxjs';

import { catchError } from 'rxjs/operators';
​

import { Person } from './person';
​

@Injectable({

  providedIn: 'root'

})

export class PersonService {​

  private apiURL = "http://localhost:8000/api/person/";
​
  httpOptions = {

     headers: new HttpHeaders({

       'Content-Type': 'application/json'

     })

  }​

  constructor(private httpClient: HttpClient) { }
​

  getAll(): Observable<Person[]> {

   return this.httpClient.get<Person[]>(this.apiURL)

   .pipe(

     catchError(this.errorHandler)

   )

 }
​

 create(person): Observable<Person> {

   return this.httpClient.post<Person>(this.apiURL, JSON.stringify(person), this.httpOptions)

   .pipe(

     catchError(this.errorHandler)

   )

 }
​

 find(id): Observable<Person> {

   return this.httpClient.get<Person>(this.apiURL + id)

   .pipe(

     catchError(this.errorHandler)

   )

 }
​

 update(id, person): Observable<Person> {

   return this.httpClient.put<Person>(this.apiURL + id, JSON.stringify(person), this.httpOptions)

   .pipe(

     catchError(this.errorHandler)

   )

 }
​

 delete(id){

   return this.httpClient.delete<Person>(this.apiURL + id, this.httpOptions)

   .pipe(

     catchError(this.errorHandler)

   )
 }​

 errorHandler(error) {

   let errorMessage = '';

   if(error.error instanceof ErrorEvent) {

     errorMessage = error.error.message;

   } else {

     errorMessage = `Error Code: ${error.status}\nMessage: ${error.message}`;

   }

   return throwError(errorMessage);

 }​

}

​8 – Components

Component Index

src/app/person/index/index.component.ts

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

import { PersonService } from '../person.service';

import { Person } from '../person';​

@Component({

  selector: 'app-index',

  templateUrl: './index.component.html',

  styleUrls: ['./index.component.css']

})

export class IndexComponent implements OnInit {​

  persons: Person[] = [];

​  // constructor() { }

  constructor(public personService: PersonService) { }​

  ngOnInit(): void {

    this.personService.getAll().subscribe((data: Person[])=>{

      this.persons = data;

      console.log(this.persons);

    })

  }​

  deletePerson(id){

    this.personService.delete(id).subscribe(res => {

         this.persons = this.persons.filter(item => item.id !== id);

         console.log('Person deleted successfully!');

    })

  }
​

}

src/app/person/index/index.component.html

<section>​

    <div class="d-flex justify-content-between">

      <h4>List person</h4>

      <a routerLink="/person/create" class="btn btn-success">Create New Person</a>

    </div>​

    <br>    

    <table class="table ">

      <tr>

        <th>ID</th>

        <th>Name</th>

        <th>Email</th>

        <th>Phone</th>

        <th width="220px">Action</th>

      </tr>

      <tr *ngFor="let person of persons">

        <td>{{ person.id }}</td>

        <td>{{ person.name }}</td>

        <td>{{ person.email }}</td>

        <td>{{ person.phone }}</td>

        <td>

          <a href="#" [routerLink]="['/person/', 'edit', person.id  ]" class="btn btn-primary">Edit</a>

          <button type="button" (click)="deletePerson(person.id)" class="btn btn-danger">Delete</button>

        </td>

      </tr>

    </table>

 </section>

Component Create

src/app/person/create/create.component.ts

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

import { PersonService } from '../person.service';

import { Router } from '@angular/router';

import { FormGroup, FormControl, Validators } from '@angular/forms';
​

@Component({

  selector: 'app-create',

  templateUrl: './create.component.html',

  styleUrls: ['./create.component.css']

})

export class CreateComponent implements OnInit {​

  form: FormGroup;​

  constructor(

    public personService: PersonService,

    private router: Router

  ) { }

​

  ngOnInit(): void {

​

    this.form = new FormGroup({

      name:  new FormControl('', [ Validators.required, Validators.pattern('^[a-zA-ZÁáÀàÉéÈèÍíÌìÓóÒòÚúÙùÑñüÜ \-\']+') ]),

      email: new FormControl('', [ Validators.required, Validators.email ]),

      phone: new FormControl('', [ Validators.required, Validators.pattern("^[0-9]*$") ])

    });​

  }​

  get f(){

    return this.form.controls;

  }​

  submit(){

    console.log(this.form.value);

    this.personService.create(this.form.value).subscribe(res => {

         console.log('Person created successfully!');

         this.router.navigateByUrl('person/index');

    })

  }​

}​

src/app/person/create/create.component.html

<div>​

  <div class="d-flex justify-content-between">

    <h4>Form customer</h4>

    <a href="#" routerLink="/person/index" class="btn btn-primaryt">Back</a>

  </div>​

  <hr/>

​    <form [formGroup]="form" (ngSubmit)="submit()">

​

        <div class="form-group row">

            <div class="col-md-6 ">

              <label for="title">Name:</label>

              <input

                formControlName="name"

                id="name"

                type="text"

                class="form-control">

              <div *ngIf="f.name.touched && f.name.invalid" class="alert alert-danger">

                  <div *ngIf="f.name.errors.required">*Name is required.</div>

                  <div *ngIf="f.name.errors.pattern">*The name must only contain letters.</div>

              </div>

            </div>

        </div>

​

        <div class="form-group row">

            <div class="col-md-6 ">

              <label for="email">Email:</label>

              <input

                formControlName="email"

                id="email"

                type="text"

                class="form-control">

              <div *ngIf="f.email.touched && f.email.invalid" class="alert alert-danger">

                  <div *ngIf="f.email.errors.required">*Email is required.</div>

                  <div *ngIf="f.email.errors.email">*The email must be a valid email address.</div>

              </div>

            </div>

        </div>

​

        <div class="form-group row">

            <div class="col-md-6 ">

              <label for="phone">Phone:</label>

              <input

                formControlName="phone"

                id="phone"

                type="text"

                class="form-control">

              <div *ngIf="f.phone.touched && f.phone.invalid" class="alert alert-danger">

                  <div *ngIf="f.phone.errors.required">*Phone is required.</div>

                  <div *ngIf="f.phone.errors.pattern">*The phone must only contain numbers.</div>

              </div>

            </div>

        </div>

​

        <button class="btn btn-primary" type="submit" [disabled]="!form.valid">Submit</button>

    </form>

</div>

​Component Edit

src/app/person/edit/edit.component.ts

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

import { PersonService } from '../person.service';

import { ActivatedRoute, Router } from '@angular/router';

import { FormGroup, FormControl, Validators} from '@angular/forms';

import { Person } from '../person';

​

@Component({

  selector: 'app-edit',

  templateUrl: './edit.component.html',

  styleUrls: ['./edit.component.css']

})

export class EditComponent implements OnInit {

​

  id: number;

  person: Person;

  form: FormGroup;

​

  constructor(

    public personService: PersonService,

    private route: ActivatedRoute,

    private router: Router

  ) { }

​

  ngOnInit(): void {

    this.id = this.route.snapshot.params['idPerson'];

    this.personService.find(this.id).subscribe((data: Person)=>{

      this.person = data;

    });

​

    this.form = new FormGroup({

      name:  new FormControl('', [ Validators.required, Validators.pattern('^[a-zA-ZÁáÀàÉéÈèÍíÌìÓóÒòÚúÙùÑñüÜ \-\']+') ]),

      email: new FormControl('', [ Validators.required, Validators.email ]),

      phone: new FormControl('', [ Validators.required, Validators.pattern("^[0-9]*$") ])

    });

​

  }

​

  get f(){

    return this.form.controls;

  }

​

  submit(){

    console.log(this.form.value);

    this.personService.update(this.id, this.form.value).subscribe(res => {

         console.log('Person updated successfully!');

         this.router.navigateByUrl('person/index');

    })

  }
​

}

​src/app/person/edit/edit.component.html

<div class="container">

  

    <div class="d-flex justify-content-between">

      <h4>Edit person</h4>

      <a href="#" routerLink="/person/index" class="btn btn-primaryt">Back</a>

    </div>

​

    <hr>

​

    <form [formGroup]="form" (ngSubmit)="submit()">

​

​

        <div class="form-group row">

            <div class="col-md-6 ">

              <label for="title">Name:</label>

              <input

                formControlName="name"

                [(ngModel)]="person.name"

                id="name"

                type="text"

                class="form-control">

              <div *ngIf="f.name.touched && f.name.invalid" class="alert alert-danger">

                  <div *ngIf="f.name.errors.required">*Name is required.</div>

                  <div *ngIf="f.name.errors.pattern">*The name must only contain letters.</div>

              </div>

            </div>

        </div>

​

        <div class="form-group row">

            <div class="col-md-6 ">

              <label for="email">Email:</label>

              <input

                formControlName="email"

                [(ngModel)]="person.email"

                id="email"

                type="text"

                class="form-control">

              <div *ngIf="f.email.touched && f.email.invalid" class="alert alert-danger">

                  <div *ngIf="f.email.errors.required">*Email is required.</div>

                  <div *ngIf="f.email.errors.email">*The email must be a valid email address.</div>

              </div>

            </div>

        </div>

​

        <div class="form-group row">

            <div class="col-md-6 ">

              <label for="phone">Phone:</label>

              <input

                [(ngModel)]="person.phone"

                formControlName="phone"

                id="phone"

                type="text"

                class="form-control">

              <div *ngIf="f.phone.touched && f.phone.invalid" class="alert alert-danger">

                  <div *ngIf="f.phone.errors.required">*Phone is required.</div>

                  <div *ngIf="f.phone.errors.pattern">*The phone must only contain numbers.</div>

              </div>

            </div>

        </div>​

        <button class="btn btn-primary" type="submit" [disabled]="!form.valid">Update</button>

    </form>

</div>​

9 – Configure person module

src/app/person/person.module.ts

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

import { CommonModule } from '@angular/common';

​

import { PersonRoutingModule } from './person-routing.module';

​

import { IndexComponent } from './index/index.component';

import { CreateComponent } from './create/create.component';

import { EditComponent } from './edit/edit.component';

​

import { FormsModule, ReactiveFormsModule } from '@angular/forms';

​

@NgModule({

  declarations: [

    IndexComponent,

    CreateComponent,

    EditComponent

  ],

  imports: [

    CommonModule,

    PersonRoutingModule,

    FormsModule,

    ReactiveFormsModule

  ]

})

export class PersonModule { }

​10 – Configure App

src/app/app.module.ts

import { BrowserModule } from '@angular/platform-browser';

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

import { HttpClientModule } from '@angular/common/http';​

import { AppRoutingModule } from './app-routing.module';

import { AppComponent } from './app.component';

​

import { PersonModule } from './person/person.module';

import { NgbModule } from '@ng-bootstrap/ng-bootstrap';

​

@NgModule({

  declarations: [

    AppComponent

  ],

  imports: [

    BrowserModule,

    AppRoutingModule,

    PersonModule,

    HttpClientModule,

    NgbModule

  ],

  providers: [],

  bootstrap: [AppComponent]

})

export class AppModule { }

src/app/app.component.html

<div class="container" style="padding:20px;">

    <h1 style="text-align:center;">

        <a href="/person/index"> Full Stack - Angular 10 & Laravel 8 </a>

    </h1>

    <hr>

  <main>

  <router-outlet></router-outlet>

  </main>

</div>

​Xem tiếp phần xây dựng Backend Laravel 8

>> Tiếp nối phần Frontend bằng Angular nay mình học Laravel 8 ( Backend )

Attach
Attachment Size
angular-10-laravel-8-main.zip383.44 KB 383.44 KB

Add new comment

Image CAPTCHA
Enter the characters shown in the image.

Related Articles

Chào mọi người, cho mình hỏi ngu phát là mình có thẻ html như span hoặc p và set contenteditable = "true"

Rất cảm ơn mọi người đã đến buổi Meet up ngày hôm nay và lắnng nghe bài nói của mình.

Cty em tuyển senior fullstack mà 5/6 ứng viên bỏ cuộc không làm được bài này

Không chạy code (pseudo code thôi), các bạn nghĩ là 2 logs này giống nhau không? Nghĩa là sẽ log TestDir instance và TestComp instance?