[ตอนที่ 15] Social App Workshop ด้วย ASP.NET Core 3 กับ Angular 9 การทำ Filtering

Line
Facebook
Twitter
Google

สารบัญเนื้อหา

  1. สร้างการ Filtering ใน API
  2. เพิ่มการ Filtering ใน SPA

1. สร้างการ Filtering ใน API

เพิ่มพารามิเตอร์ UserId, Gender ใน UserParams.cs เพื่อส่งไป Filter ใน API โดย UserId จะใช้สำหรับดึงข้อมูลโปรไฟล์ของสมาชิกที่เป็นผู้ใช้งาน เพื่อนำข้อมูลไป Filter สมาชิกคนอื่น ๆ และ Gender จะใช้ Filter เพศของสมาชิก

namespace SocialApp_API.Helpers
{
    public class UserParams
    {
        private const int MaxPageSize = 50;
        public int PageNumber { get; set; } = 1;
        private int pageSize = 10;
        public int PageSize
        { 
            get { return pageSize; }
            set { pageSize = (value > MaxPageSize) ? MaxPageSize : value; }
        }

        public int UserId { get; set; }
        public string Gender { get; set; }
    }
}

เพิ่ม Filter ใน GetUsers() ใน UsersController.cs

public async Task<IActionResult> GetUsers([FromQuery]UserParams userParams)
{
    var currentUserId = int.Parse(User.FindFirst(ClaimTypes.NameIdentifier).Value);

    var userFromRepo = await _repo.GetUser(currentUserId);

    userParams.UserId = currentUserId;

    if (string.IsNullOrEmpty(userParams.Gender))
    {
        userParams.Gender = userFromRepo.Gender == "male" ? "female" : "male";
    }

    var users = await _repo.GetUsers(userParams);

    var usersToReturn = _mapper.Map<IEnumerable<UserForListDto>>(users);

    Response.AddPagination(users.CurrentPage, users.PageSize, users.TotalCount, users.TotalPages);

    return Ok(usersToReturn);
}

ปรับปรุง GetUsers() ใน SocialRepository.cs

public async Task<PagedList<User>> GetUsers(UserParams userParams)
{
    var users = _context.Users.Include(p => p.Photos).AsQueryable();

    users = users.Where(u => u.Id == userParams.UserId);

    users = users.Where(u => u.Gender == userParams.Gender);

    return await PagedList<User>.CreateAsync(users, userParams.PageNumber, userParams.PageSize);
}

ลองเรียก API
http://localhost:5000/api/users
http://localhost:5000/api/users?gender=female
ซึ่งจะพบว่าเราสามารถ Filter ข้อมูลได้ตามเงื่อนไขแล้ว

เพิ่มพารามิเตอร์ MinAge, MaxAge ใน UserParams.cs

namespace SocialApp_API.Helpers
{
    public class UserParams
    {
        private const int MaxPageSize = 50;
        public int PageNumber { get; set; } = 1;
        private int pageSize = 10;
        public int PageSize
        { 
            get { return pageSize; }
            set { pageSize = (value > MaxPageSize) ? MaxPageSize : value; }
        }

        public int UserId { get; set; }
        public string Gender { get; set; }
        public int MinAge { get; set; } = 18;
        public int MaxAge { get; set; } = 99;
    }
}

ปรับปรุง GetUsers() ใน SocialRepository.cs อีกครั้ง

public async Task<PagedList<User>> GetUsers(UserParams userParams)
{
    var users = _context.Users.Include(p => p.Photos).AsQueryable();

    users = users.Where(u => u.Id == userParams.UserId);

    users = users.Where(u => u.Gender == userParams.Gender);

    if (userParams.MinAge != 18 || userParams.MaxAge != 99)
    {
        var minDob = DateTime.Today.AddYears(-userParams.MaxAge - 1);
        var maxDob = DateTime.Today.AddYears(-userParams.MinAge);

        users = users.Where(u => u.DateOfBirth >= minDob && u.DateOfBirth <= maxDob);
    }

    return await PagedList<User>.CreateAsync(users, userParams.PageNumber, userParams.PageSize);
}

ลองเรียก API
http://localhost:5000/api/users
http://localhost:5000/api/users?minAge=24
http://localhost:5000/api/users?minAge=24&maxAge=34
ซึ่งจะพบว่าเราสามารถ Filter ข้อมูลได้ตามเงื่อนไขแล้ว

2. เพิ่มการ Filtering ใน SPA

เพิ่ม Filter ใน member-list.component.html

<div class="text-center mt-3">
  <h2>Your matches - {{pagination.totalItems}} found</h2>
</div>

<div class="container mt-3">
  <form class="form-inline" novalidate>
    <div class="form-group">
      <label for="minAge">Age From</label>
      <input type="number" class="form-control ml-1" style="width: 70px" id="minAge" name="minAge">
    </div>
  
    <div class="form-group px-2">
      <label for="maxAge">Age To</label>
      <input type="number" class="form-control ml-1" style="width: 70px" id="maxAge" name="maxAge">
    </div>
  
    <div class="form-group px-2">
      <label for="gender">Show: </label>
      <select class="form-control ml-1" style="width: 130px" id="gender" name="gender">
        <option>
  
        </option>
      </select>
    </div>
    <button type="submit" class="btn btn-primary" style="margin-left:10px">Apply Filters</button>
    <button type="button" class="btn btn-info" style="margin-left:10px">Reset Filter</button>
  
  </form>
  <br>

  <div class="row">
    <div *ngFor="let user of users" class="col-lg-2 col-md-3 col-sm-6">
      <app-member-card [user]="user"></app-member-card>
    </div>
  </div>
</div>

<div class="d-flex justify-content-center">
  <pagination [boundaryLinks]="true"
              [totalItems]="pagination.totalItems"
              [itemsPerPage]="pagination.itemsPerPage"
              [(ngModel)]="pagination.currentPage"
              (pageChanged)="pageChanged($event)"
            previousText="‹" nextText="›" firstText="«" lastText="»">
  </pagination>
</div>

เพิ่มโค้ดดึงข้อมูลสมาชิกที่ login จาก localStorage ใน member-list.component.ts

user: User = JSON.parse(localStorage.getItem('user'));

เพิ่ม genderList เพื่อเอาไปเป็นตัว Filter ใน html ใน member-list.component.ts

genderList = [{value: 'male', display: 'Males'}, {value: 'female', display: 'Females'}];

เพิ่ม userParams เพื่อรับค่า Filter จาก html ใน member-list.component.ts

userParams: any = {};

เพิ่มการกำหนดค่าพารามิเตอร์ใน onInit() ของ member-list.component.ts

this.userParams.gender = this.user.gender === 'female' ? 'male' : 'female';
this.userParams.minAge = 18;
this.userParams.maxAge = 99;

เพิ่ม resertFilters() ใน member-list.component.ts

resetFilters() {
  this.userParams.gender = this.user.gender === 'female' ? 'male' : 'female';
  this.userParams.minAge = 18;
  this.userParams.maxAge = 99;
  this.loadUsers();
}

เพิ่มการรับ userParams ใน GetUsers() ของ user.service.ts

import { Injectable } from '@angular/core';
import { environment } from 'src/environments/environment';
import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http';
import { Observable } from 'rxjs';
import { User } from '../_models/user';
import { PaginatedResult } from '../_models/pagination';
import { map } from 'rxjs/operators';

@Injectable({
  providedIn: 'root'
})
export class UserService {
  baseUrl = environment.apiUrl;

  constructor(private http: HttpClient) { }

  getUsers(page?, itemsPerPage?, userParams?): Observable<PaginatedResult<User[]>> {
    const paginatedResult: PaginatedResult<User[]> = new PaginatedResult<User[]>();

    let params = new HttpParams();

    if (page != null && itemsPerPage != null) {
      params = params.append('pageNumber', page);
      params = params.append('pageSize', itemsPerPage);
    }

    if (userParams != null) {
      params = params.append('minAge', userParams.minAge);
      params = params.append('maxAge', userParams.maxAge);
      params = params.append('gender', userParams.gender);
    }

    return this.http.get<User[]>(this.baseUrl + 'users', { observe: 'response', params })
      .pipe(
        map(response => {
          paginatedResult.result = response.body;
          if (response.headers.get('Pagination') != null) {
            paginatedResult.pagination = JSON.parse(response.headers.get('pagination'));
          }
          return paginatedResult;
        })
      );
  }

  getUser(id): Observable<User> {
    return this.http.get<User>(this.baseUrl + 'users/' + id);
  }

  updateUser(id: number, user: User) {
    return this.http.put(this.baseUrl + 'users/' + id, user);
  }

  setMainPhoto(userId: number, id: number) {
    return this.http.post(this.baseUrl + 'users/' + userId + '/photos/' + id + '/setMain', {});
  }

  deletePhoto(userId: number, id: number) {
    return this.http.delete(this.baseUrl + 'users/' + userId + '/photos/' + id);
  }

}

เพิ่มการส่งค่า userParams ใน loadUsers() ของ member-list.component.ts

loadUsers() {
  this.userService
    .getUsers(this.pagination.currentPage, this.pagination.itemsPerPage, this.userParams)
    .subscribe((res: PaginatedResult<User[]>) => {
    this.users = res.result;
    this.pagination = res.pagination;
  }, error => {
    this.alertify.error(error);
  });
}

โค้ดฉบับเต็มของ member-list.component.ts

import { Component, OnInit } from '@angular/core';
import { User } from '../../_models/user';
import { UserService } from '../../_services/user.service';
import { AlertifyService } from '../../_services/alertify.service';
import { ActivatedRoute } from '@angular/router';
import { Pagination, PaginatedResult } from 'src/app/_models/pagination';

@Component({
  selector: 'app-member-list',
  templateUrl: './member-list.component.html',
  styleUrls: ['./member-list.component.css']
})
export class MemberListComponent implements OnInit {
  users: User[];
  user: User = JSON.parse(localStorage.getItem('user'));
  genderList = [{value: 'male', display: 'Males'}, {value: 'female', display: 'Females'}];
  userParams: any = {};
  pagination: Pagination;

  constructor(private userService: UserService, private alertify: AlertifyService, private route: ActivatedRoute) { }

  ngOnInit() {
    this.route.data.subscribe(data => {
      this.users = data.users.result;
      this.pagination = data.users.pagination;
    });

    this.userParams.gender = this.user.gender === 'female' ? 'male' : 'female';
    this.userParams.minAge = 18;
    this.userParams.maxAge = 99;
  }

  resetFilters() {
    this.userParams.gender = this.user.gender === 'female' ? 'male' : 'female';
    this.userParams.minAge = 18;
    this.userParams.maxAge = 99;
    this.loadUsers();
  }

  pageChanged(event: any): void {
    this.pagination.currentPage = event.page;
    this.loadUsers();
  }

  loadUsers() {
    this.userService
      .getUsers(this.pagination.currentPage, this.pagination.itemsPerPage, this.userParams)
      .subscribe((res: PaginatedResult<User[]>) => {
      this.users = res.result;
      this.pagination = res.pagination;
    }, error => {
      this.alertify.error(error);
    });
  }

}

ปรับปรุงให้ member-list.component.html ให้รองรับการ Filter

<div class="text-center mt-3">
  <h2>Your matches - {{pagination.totalItems}} found</h2>
</div>

<div class="container mt-3">
  <form class="form-inline" #form="ngForm" (ngSubmit)="loadUsers()" novalidate>
    <div class="form-group">
      <label for="minAge">Age From</label>
      <input type="number" class="form-control ml-1" style="width: 70px" id="minAge"
        [(ngModel)]="userParams.minAge" name="minAge">
    </div>
  
    <div class="form-group px-2">
      <label for="maxAge">Age To</label>
      <input type="number" class="form-control ml-1" style="width: 70px" id="maxAge"
      [(ngModel)]="userParams.maxAge" name="maxAge">
    </div>
  
    <div class="form-group px-2">
      <label for="gender">Show: </label>
      <select class="form-control ml-1" style="width: 130px" id="gender"
      [(ngModel)]="userParams.gender" name="gender">
        <option *ngFor="let gender of genderList" [value]="gender.value">
          {{gender.display}}
        </option>
      </select>
    </div>
    <button type="submit" class="btn btn-primary" style="margin-left:10px">Apply Filters</button>
    <button type="button" class="btn btn-info" (click)="resetFilters()" style="margin-left:10px">Reset Filter</button>
  
  </form>
  <br>

  <div class="row">
    <div *ngFor="let user of users" class="col-lg-2 col-md-3 col-sm-6">
      <app-member-card [user]="user"></app-member-card>
    </div>
  </div>
</div>

<div class="d-flex justify-content-center">
  <pagination [boundaryLinks]="true"
              [totalItems]="pagination.totalItems"
              [itemsPerPage]="pagination.itemsPerPage"
              [(ngModel)]="pagination.currentPage"
              (pageChanged)="pageChanged($event)"
            previousText="‹" nextText="›" firstText="«" lastText="»">
  </pagination>
</div>

ทดสอบรันและใช้งาน

Line
Facebook
Twitter
Google
การติดตั้งและใช้งาน Datatables ร่วมกับ Angular
[ตอนที่ 16] Social App Workshop ด้วย ASP.NET Core 3 กับ Angular 9 การทำ Sorting
[ตอนที่ 15] Social App Workshop ด้วย ASP.NET Core 3 กับ Angular 9 การทำ Filtering
[ตอนที่ 14] Social App Workshop ด้วย ASP.NET Core 3 กับ Angular 9 การใช้งาน Paging
เตรียม Atom สำหรับ React Native #3
เตรียม Visual Studio Code สำหรับ React Native #2
การติดตั้ง React Native บน macOs #1
การกำหนดค่า TF_MIN_GPU_MULTIPROCESSOR_COUNT เพื่อให้ TensorFlow ใช้งาน GPU ทุกตัว
ติดตั้ง Ubuntu 17.04 ใช้งานร่วมกับ Windows 10
การติดตั้ง TensorFlow & Caffe บน Ubuntu 16.04