Hiện sản phẩm theo loại dùng Angular

Hiện sản phẩm theo loại dùng Angular hướng dẫn thực hiện code để tạo component hiện các sản phẩm trong 1 loại nào đó và phân trang….


Yêu cầu

  1. Lấy sản phẩm theo loại , có hiện tên loại, link đến chức năng này từ tên loại đã hiện trên layout
  2. Thực hiện phân trang danh sách sản phẩm
  3. Trước khi thực hiện bài này, hãy xem bài sau và thực hiện theo đó trước nhé: https://longnv.name.vn/thuc-tap-angular/hien-loai-san-pham-dung-angular

Chuẩn bị thực hiện

  1. Chạy project Angular : Vào folder project và chạy lệnh sau
     ng serve -o 
  2. Chạy Json server: Vào folder project và chạy lệnh 
    json-server -w db.json

Tạo component sản phẩm theo loại

Trong folder project chạy lệnh ng g c SanPhamTheoLoai

Tạo routing cho component

Trên trang chủ, user nhắp tên 1 loại, sẽ hiện ra danh sách các sản phẩm trong loại vừa mới nhắp. Do đó giờ cần đến địa chỉ (path) mới. Mở file app-routing.module.ts và định nghĩa path loai trong mục routes (path có tham số là id của loại)

Test: Mở địa chỉ http://localhost:4200/loai/1 và thấy component hiện ra là đúng.

Tạo hàm trong service để request dữ liệu từ server

Giờ thì tạo hàm để lấy dữ liệu từ server xuống. Chúng ta định nghĩa trong service cho có tính tập trung. Định nghĩa 2 hàm, 1 hàm lấy sản phẩm của loại, còn 1 hàm sẽ lấy tên loại từ server xuống.

//du-lieu.service.ts
getSanPhamTheoLoai(idLoai:Number=0) { 
    var url = `http://localhost:3000/sanpham?idLoai=${idLoai}&_sort=ngay&_order=desc`;
    return this.h.get<any>(url, {observe: 'response'});
}
getTenLoaiSanPham(idLoai:Number=0){
    var url = `http://localhost:3000/loaisp?id=${idLoai}`;
    return this.h.get<ILoaisp[]>(url);
}

Gọi hàm trong trong servive từ component

Trong component sản phẩm theo loại , gọi các hàm trong service để có dữ liệu mà trình bày. Mở file san-pham-theo-loai.component.ts và code:

//san-pham-theo-loai.component.ts
import { Component } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { DuLieuService } from '../du-lieu.service';
import { ISanpham } from '../isanpham';
@Component({ selector: 'app-san-pham-theo-loai',
  templateUrl: './san-pham-theo-loai.component.html',
  styleUrls: ['./san-pham-theo-loai.component.css']
})
export class SanPhamTheoLoaiComponent {
  listSanPham:ISanpham[]=[]; 
  tenLoai:string=""; 
  idLoai:number=0;  
  constructor( 
     private d:DuLieuService, 
     private route:ActivatedRoute
  ) { }
  ngOnInit(): void {
    this.idLoai = Number( this.route.snapshot.params['id'] );
    this.d.getTenLoaiSanPham(this.idLoai).subscribe ( 
      loai =>  { this.tenLoai= loai[0].tenLoai; }    
    );
    this.d.getSanPhamTheoLoai(this.idLoai).subscribe ( 
      res =>  this.listSanPham = res 
    );
  }
}

Hiện sản phẩm theo loại dùng Angular ra view

Sau khi component gọi hàm, các biến sẽ có giá trị , giờ thì trong view sẽ hiện ra . Chúng ta sử dụng card-group của bootstrap 5: https://getbootstrap.com/docs/5.3/components/card/#card-groups

<!-- san-pham-theo-loai.component.html -->
<h2 class="bg-success p-2 text-white h3">
    SẢN PHẨM TRONG LOẠI {{ tenLoai | uppercase}} 
</h2>
<div class="row  row-cols-1  row-cols-md-2 row-cols-xl-3 g-2">
    <div class="col" *ngFor="let sp of listSanPham" >
        <div class="card text-center">
            <div class="card-header">
                <h3 class="h4" style="height:45px">{{sp.tensp}}</h3>
            </div>
            <div class="card-body">             
              <img class="img-fluid" src="{{sp.hinh}}">
              <p class="h5 mt-3">
                 Giá : {{sp.giasp|number:'1.0-0':'fr' }} VNĐ
              </p>
            </div>
            <div class="card-footer">
                <a href="#">Xem chi tiết</a>
            </div>
        </div>  
    </div>
</div>

Xem thử kết quả: http://localhost:4200/loai/1 sẽ thấy dữ liệu hiện ra theo id của loại:

Tại tên các loại trên layout, chúng ra tạo link đến chức năng này. Mở file view cac-loai.component.html để tạo link

<!-- cac-loai.component.html -->
<ul class="list-group">
    <li class="list-group-item py-2" *ngFor="let loai of listLoaiSP">
      <a href="/loai/{{loai.id}}"> {{loai.tenLoai | uppercase }}</a>
    </li>
</ul>

Thực hiện phân trang

Phân trang là chia khúc (trang) danh sách các record để user không rối khi dữ liệu quá nhiều

1. Cài đặt module ngx-pagination

Chạy lệnh sau trong folder project : npm install ngx-pagination

2. Nhúng module vào project

Mở file app.modules.ts và khai báo

3. Trong hàm lấy dữ liệu server: chỉ lấy 1 trang

Hàm lấy sản phẩm cần có điều chình :

  • Thêm tham số pageNum – số trang cần lấy, pageSize – số record trong 1 trang.
  • Request gửi lên server bổ sung thêm biến _page_limit.  
  • Sử dụng {observe:’response’} khi request để lấy giá trị trong http header của response – trong đó có biến X-Total-Count
//du-lieu.service.ts
getSanPhamTheoLoai(idLoai:Number=0, pageSize:number=1, pageNum:number=1) { 
  var url = `http://localhost:3000/sanpham?idLoai=${idLoai}&_sort=ngay&order=desc`;
  url+= `&_page=${pageNum}&_limit=${pageSize}`;
  return this.h.get<any>(url , {observe: 'response'} );
}

4. Trong component: Tạo các biến và các hàm dùng cho phân trang

  • Khai báo các biến pageNum – trang hiện hành, pageSize – số record trong 1 trang, total – tổng số record
  • Khi gọi hàm getSanPhamTheoLoai: truyền tham số pageSize, pageNum
  • Khi nhận response :  lấy res.body lưu vào listSanPham và lấy biến X-Total-Count trong header lưu vào total (do json -server trả về )
//san-pham-theo-loai.component.ts
... 
export class SanPhamTheoLoaiComponent {
  listSanPham:ISanpham[]=[];  tenLoai:string="";  idLoai:number=0;  
  pageNum:number=1;
  pageSize:number=2;
  total: number = 0;  
...
this.d.getSanPhamTheoLoai(this.idLoai, this.pageSize,this.pageNum ).subscribe ( 
     res => {
        this.listSanPham  = res.body ;
        this.total = Number(res.headers.get('X-Total-Count'));
      } 
);
  • Trong component (sau hàm ngInit) định nghĩa hàm chuyển đến trang để khi user click chọn 1 page thì gán giá trị mới cho pageNum và request lại
chuyenDenTrang( p: number){
    this.pageNum = p;
     this.d.getSanPhamTheoLoai(this.idLoai, this.pageSize, this.pageNum).subscribe ( 
      res => {
        this.listSanPham  = res.body ;
        this.total = Number(res.headers.get('X-Total-Count'));
      }
     );
}

Mở file san-pham-theo-loai.component.html

  • Thêm lệnh paginate lúc lặp:
| paginate: { itemsPerPage: pageSize, currentPage: pageNum, totalItems: total}
  • Cho hiện các link phân trang với lệnh
<pagination-controls (pageChange)="chuyenDenTrang($event)"
    previousLabel="Trước" nextLabel="Sau" [autoHide]="true" [responsive]="true">
</pagination-controls>

Test: Xem lại sẽ thấy thanh phân trang


Sau đây là các bài trong seris thực tập Angular bạn cần thực hiện tuần tự từ trên xuống để có project nhé:

  1. Đôi điều về Angular – P1
  2. Đôi điều về Angular – P2
  3. Hiện sản phẩm bán chạy
  4. Hiện sản phẩm mới dùng Angular
  5. Hiện loại sản phẩm dùng Angular
  6. Hiện sản phẩm theo loại dùng Angular
  7. Hiện chi tiết sản phẩm dùng Angular