สารบัญเนื้อหา
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>
ทดสอบรันและใช้งาน