به نام خدا. در این آموزش قصد دارم نحوه ی پیاده سازی سمت Front End قابلیت های Pagination و Sort و Search در جداول با Angular 8 و Bootstrap 4 و اتصال به سرور ASP.net Core را خدمتتان ارائه کنم. این آموزش بخش دوم آموزش پیاده سازی قابلیت های Pagination و Sort و Search است. در بخش اول به پیاده سازی قابلیت های مذکور در سمت سرور با ASP.net Core و Entity Framework Core پرداختیم. برای مطالعه ی آموزش اول به لینک زیر مراجعه کنید:
کدهای این آموزش (هم کدهای سمت سرور با ASP.net Core و هم کدهای سمت کاربر با Angular 8 و Bootstrap 4) را می توانید از لینک زیر به صورت رایگان دانلود و استفاده کنید.
کدهای این آموزش در آدرس زیر قابل مشاهده و دانلود است
https://github.com/MohammadMoeinFazeli/ASP.NetCore-Angular8-PaginationSortingFiltering
برای شروع باید ابتدا یک پروژه ی جدید با Angular 8 ایجاد کنید. بدین منظور می توانید از آموزش زیر استفاده کنید:
– ایجاد اولین پروژه با Angular 8: ماشین حساب ساده
پس از ایجاد پروژه ی جدید با انگولار 8 برای افزودن Bootstarp به پروژه از بسته ی ng-bootstrap استفاده می کنیم. برای نصب این بسته و افزودن آن به پروژه ی خود، دستور زیر را در خط فرمان درحالی که در مسیر مربوط به پروژه هستید اجرا کنید:
npm install --save @ng-bootstrap/ng-bootstrap
از آنجا که بسته ی ng-bootstrap به فایل CSS مربوط به فریمروک Bootstrap نیاز دارد، باید آن را به پروژه ی خود اضافه کنید. همچنین برای استفاده از فونت های Font Awesome لینک مربوط به آن را نیز باید به پروژه اضافه کنید. بدین منظور کدهای زیر را در فایل src/index.html قرار دهید:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>StudentListUi</title>
<base href="/" />
<!-- Bootstrap -->
<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" />
<!-- fontawesome -->
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.6.3/css/all.css" integrity="sha384-UHRtZLI+pbxtHCWp1t77Bi1L4ZtiqrqD80Kn4Z8NTSRyMA2Fd33n5dQ8lWUE00s/" crossorigin="anonymous" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" type="image/x-icon" href="favicon.ico" />
</head>
<body>
<app-root></app-root>
</body>
</html>
اکنون برای افزودن ماژولهای ng-bootstrap همراه با سایر ماژول های مورد نیاز یعنی ماژول ارسال درخواست های http (یعنی HttpClientModule) و ماژول کار با فرم در انگولار (یعنی FormsModule) به app.module خود کدهای زیر را در فایل src/app/app.module.ts قرار دهید:
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { HttpClientModule } from '@angular/common/http';
import { FormsModule } from '@angular/forms';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { AppComponent } from './app.component';
@NgModule({
declarations: [AppComponent],
imports: [BrowserModule, HttpClientModule, FormsModule, NgbModule],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule {}
برای بهتر شدن کیفیت کار خود حتما از قابلیت های interface در انگولار استفاده کنید. برای تعیین کردن نوع داده های دریافتی از سمت سرور دو interface با نام های IStudent و IResult را با استفاده از کدهای زیر در فایل src/app/app.interface.ts (که باید آن را ایجاد کنیم) پیاده سازی می کنیم.
export interface IStudent {
studentId: number;
name: string;
family: string;
}
export interface IResult {
results: Array<IStudent>;
currentPage: number;
pageCount: number;
pageSize: number;
rowCount: number;
firstRowOnPage: number;
lastRowOnPage: number;
}
در قدم بعد به سراغ پیاده سازی منطق برنامه ی می رویم. بدین منظور کدهای زیر را در فایل src/app/app.component.ts قرار دهید. در این کدها تابع requestData با فراخوانی api سمت سرور و ارسال پارامترهای مناسب (که با متغییرهای مربوط به خود در ارتباط هستند و بدلیل تاخیر در مقدار دهی متغییرها از timeout نیز استفاده کرده ایم) داده هایی که باید در جدول نمایش داده شوند را می گیرد و متغییرهای مربوطه را مقداردهی می کند.
import { Component, OnInit, ViewChildren, QueryList } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { IStudent, IResult } from './app.interface';
import { NgbdSortableDirective, SortEvent } from './sortable.directive';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
@ViewChildren(NgbdSortableDirective) headers: QueryList<
NgbdSortableDirective
>;
Students: Array<IStudent>;
page = 1;
pageSize = 4;
collectionSize: number;
searchTerm = '';
sortDirection = '';
sortFiled = '';
constructor(private http: HttpClient) {}
ngOnInit() {
this.requestData();
}
requestData() {
setTimeout(() => {
const params = {
filed: this.sortFiled,
sortDirection: this.sortDirection,
term: this.searchTerm,
page: this.page.toString(),
pageSize: this.pageSize.toString()
};
this.http
.get<IResult>('http://localhost:60285/api/Student', { params })
.subscribe(
result => {
this.Students = result.results;
this.page = result.currentPage;
this.collectionSize = result.rowCount;
this.pageSize = result.pageSize;
},
error => {
console.log(error);
}
);
});
}
onSort({ column, direction }: SortEvent) {
// resetting other headers
this.headers.forEach(header => {
if (header.sortable !== column) {
header.direction = '';
}
});
this.sortDirection = direction;
this.sortFiled = column;
this.requestData();
}
}
سپس برای پیاده سازی بخش قالب کامپوننت مدنظر کدهای زیر را در فایل src/app/app.component.html قرار دهید. در این کدها جدول و بخش فیلتر داده ها و نوار pagination و منوی کشویی انتخاب تعداد آیتم های درون جدول آمده است. همچنین تک تک بخش های مور نیاز از طریق قابلیت Data Binding انگولار به منطق برنامه متصل شده اند.
<div class="mx-5 my-5">
<div class="form-group form-inline">
Full search:
<input class="form-control ml-2" type="text" name="searchTerm" [(ngModel)]="searchTerm" />
<button class="btn btn-info ml-2" (click)="requestData()">Filter</button>
</div>
<table class="table table-striped">
<thead>
<tr class="row">
<th class="col-2" scope="col">Id</th>
<th class="col" style="cursor: pointer;" scope="col" sortable="name" (sort)="onSort($event)" > name </th>
<th class="col" style="cursor: pointer;" scope="col" sortable="family" (sort)="onSort($event)" > family </th>
</tr>
</thead>
<tbody>
<tr class="row" *ngFor="let Student of Students">
<th class="col-2" scope="row">{{ Student.studentId }}</th>
<td class="col"> {{ Student.name }} </td>
<td class="col">{{ Student.family }}</td>
</tr>
</tbody>
</table>
<div class="d-flex justify-content-between p-2">
<ngb-pagination [collectionSize]="collectionSize" (pageChange)="requestData()" [(page)]="page" [pageSize]="pageSize" [directionLinks]="false" >
</ngb-pagination>
<select class="custom-select" style="width: auto" name="pageSize" [(ngModel)]="pageSize" (change)="requestData()" >
<option [ngValue]="2">2 items per page</option>
<option [ngValue]="4">4 items per page</option>
<option [ngValue]="6">6 items per page</option>
</select>
</div>
</div>
برای پیاده سازی ظاهر کامپوننت مدنظر نیز کدهای زیر را در فایل src/app/app.component.css قرار دهید. این استایل ها برای نمایش علامت فلش رو به بالا یا پایین در کنار نام ستون جدول در هنگام کلیک کاربر روی آن ها برای sort (مرتب سازی) است.
.asc:before {
font-family: 'Font Awesome 5 Free';
content: '\f30c';
display: inline-block;
padding-right: 3px;
vertical-align: middle;
font-weight: 900;
}
.desc:before {
font-family: 'Font Awesome 5 Free';
content: '\f309';
display: inline-block;
padding-right: 3px;
vertical-align: middle;
font-weight: 900;
}
خوب تا اینجا عالی است. البته در کدها همانطور که متوجه شدید از یک directive هم استفاده شده است. برای پیاده سازی این دایرکتیو، فایل src/app/sortable.directive.ts را ایجاد و کدهای زیر را درون آن قرار دهید. این دایرکتیو اقدامات مربوط به sort و انتساب کلاس های مناسب (asc برای مرتب سازی صعودی و desc برای مرتب سازی نزولی به ستون مدنظر در جدول) است.
import { Directive, EventEmitter, Input, Output } from '@angular/core';
export type SortDirection = 'asc' | 'desc' | '';
const rotate: { [key: string]: SortDirection } = {
asc: 'desc',
desc: '',
'': 'asc'
};
export interface SortEvent {
column: string;
direction: SortDirection;
}
@Directive({
selector: 'th[sortable]',
host: {
'[class.asc]': 'direction === "asc"',
'[class.desc]': 'direction === "desc"',
'(click)': 'rotate()'
}
})
export class NgbdSortableDirective {
@Input() sortable: string;
@Input() direction: SortDirection = '';
@Output() sort = new EventEmitter<SortEvent>();
rotate() {
this.direction = rotate[this.direction];
this.sort.emit({ column: this.sortable, direction: this.direction });
}
}
برای افزودن directive ایجاد شده به ماژول اصلی خود، کدهای زیر را در فایل app.module قرار دهید:
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { HttpClientModule } from '@angular/common/http';
import { FormsModule } from '@angular/forms';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { AppComponent } from './app.component';
import { NgbdSortableDirective } from './sortable.directive';
@NgModule({
declarations: [AppComponent, NgbdSortableDirective],
imports: [BrowserModule, HttpClientModule, FormsModule, NgbModule],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule {}
اکنون پروژه ی شما کاملا آماده و قابل استفاده است، برای دیدن خروجی می توانید دستور ng serve را در خط فرمان و در حالی که در پوشه ی مربوط به پروژه هستید اجرا کنید.. اکنون مرورگر را باز کنید و به آدرس http://localhost:4200 بروید. اگر پروژه ی سمت سرور را نیز اجرا کرده باشید (برای مشاهده ی آموزش مربوطه، به این لینک مراجعه کنید) ظاهر خروجی برنامه به صورت زیر است:
همانطور که در خروجی مشاهده می کنید یک جدول حاوی اطلاعاتی در مورد دانشجویان(که از سرور گرفته می شود)، فیلدی برای ورود عبارت جستجو و همچنین دکمه جستجو، نوار مربوط به pagination در زیر جدول و یک منوی کشویی انتخاب تعداد آیتم های درون جدول در خروجی کامپوننت پیاده سازی شده قرار دارد. همچنین با کلیک روی سربرگ ستون های name و family، مقادیر جدول متناسب با آن فیلد به صورت صعودی یا نزولی یا بدون تغییر مرتب می شود. با استفاده از هرکدام از این قابلیت ها، داده های مربوطه از سمت سرور فراخوانی شده و در جدول قرار می گیرد.
امیدوارم این آموزش برای شما مفید باشد. مجددا یادآوری می کنم کدهای این آموزش از طریق این لینک قابل دانلود و استفاده است.
موفق باشید. التماس دعا
با سلام و احترام
آیا میتونیم این بخش رو بدون آنگولار هم پیاده سازی کنیم. به تنهایی با استفاده از بوت استرپ یا مثلا استفاده از بوت استرپ و جاوا اسکریپت.
ممنون میشم راهنمایی کنید.
با سلام و عرض ادب
بله اصلا نیازی به انگولار نیست، با جاوااسکریپت (با کمک کلاس XMLHttpRequest) یا با JQuery (با کمک تابع Ajax) و سایر فریمورک ها نیز به جای انگولار، می توان این بخش را انجام داد.
سوالی باشد در خدمتم.
موفق باشید…