[筆記][angular][排序] angular 2 / 4 查詢畫面增加 排序功能

之前的「[筆記][Angular 2][Angular 4]透過Angular-CLI 撰寫 Angular 2針對單一資料表的CRUD」,內容作了針對單一資料表的C(新增)R(查詢)U(修改)D(刪除)。其中查詢的部分,也加上分頁的功能。但,感覺好像還缺了那一塊。一般的查詢,可能還需要額外加上『排序』,在分頁的情況下,可以針對每個欄位,點選排序,進行『順排(由小到大)』與『逆排(由大到小)』的排序。這邊就來補充這個份的功能。

 

緣起:

之前的「[筆記][Angular 2][Angular 4]透過Angular-CLI 撰寫 Angular 2針對單一資料表的CRUD」,內容作了針對單一資料表的C(新增)R(查詢)U(修改)D(刪除)。其中查詢的部分,也加上分頁的功能。但,感覺好像還缺了那一塊。一般的查詢,可能還需要額外加上『排序』,在分頁的情況下,可以針對每個欄位,點選排序,進行『順排(由小到大)』與『逆排(由大到小)』的排序。這邊就來補充這個份的功能。相關程式碼,修改前的相關內容,請參考之前的這一篇『[筆記][Angular 2][Angular 4]透過Angular-CLI 撰寫 Angular 2針對單一資料表的CRUD

WebAPI  的部分

取得分頁內容中,我們新增了兩個參數,分別是

  • 排序的欄位:orderByField
  • 排序的方向:orderByDirection
    • 順排:ASC
    • 逆排:DESC

在排序的地方,判斷傳入的是否為主索引,如果不是主索引,由於可能會造成每次查詢的順序不同,因此,非主索引的排序,要再加上主索引的排序條件在次要排序。相關程式碼如下:

''' <summary>
''' 依據傳入的第幾頁(PageNum)、頁面筆數(PageSize),傳回該分頁的相關資料物件集合
''' </summary>
''' <param name="PageNum">第幾頁</param>
''' <param name="PageSize">頁面筆數</param>
''' <param name="orderByField">排序欄位</param>
''' <param name="orderByDirection">排序方向</param>
''' <returns>
''' 成功回傳資料物件集合oProds
''' </returns>
Public Function GetProdsByPage(ByVal PageNum As Integer, ByVal PageSize As Integer, ByVal orderByField As String, ByVal orderByDirection As String) As List(Of ProductInfo)
	'Throw New NotImplementedException()
	Dim oProds As New List(Of ProductInfo)
	Try
		Dim ConnStr As String = GetConnStr()
		Using Conn As New SqlConnection(ConnStr)
			Dim SqlTxt As String = ""
			SqlTxt &= " SELECT *  "
			SqlTxt &= " FROM  "
			SqlTxt &= " ( "
			SqlTxt &= "     SELECT ROW_NUMBER() OVER ( ORDER BY " & orderByField & " " & orderByDirection
			If orderByField <> "ProductID" Then
				'排序欄位不是PK,要加上PK的欄位
				SqlTxt &= " , ProductID "
			End If
			SqlTxt &= " ) AS RowNumber, *  "
			SqlTxt &= " 	FROM Products (NOLOCK) "
			SqlTxt &= " ) AS P "
			SqlTxt &= " WHERE RowNumber BETWEEN @PageSize*(@PageNum-1)+1 AND @PageSize*@PageNum "
			SqlTxt &= "  "

			oProds = Conn.Query(Of ProductInfo)(SqlTxt, New With {.PageSize = PageSize, .PageNum = PageNum})
		End Using
	Catch ex As Exception
		Throw New Exception(ex.Message)
	End Try
	Return oProds
End Function

 

Service 相關

修改前的相關內容,請參考之前的這一篇『[筆記][Angular 2][Angular 4]透過Angular-CLI 撰寫 Angular 2針對單一資料表的CRUD

首先,增加兩個屬性,來存放當下的「排序欄位」、「排序方向」

  //排序;
  orderByField:string='ProductID';  //目前排序的欄位名稱
  orderByDirection:string='ASC';    //順排:ASC,逆排:DESC

接著,增加排序相關的三個function

//排序相關開始
  //設定排序的欄位
  SetOrderBy(FieldName){
    if(this.orderByField==FieldName){
      //如果傳入的欄位名稱==目前的排序欄位名稱
      //切換順排或逆排
      this.toggleDirection();
    }
    else{
      //傳入的欄位名稱與目前的排序欄位不同

      //設定排目前排序的欄位名稱
      this.orderByField = FieldName;
      //預設為順排
      this.orderByDirection='ASC';
    }
    //重新取得資料
    this.GetDatasByPage(this.currentPageNum);
  }

  //切換順排或逆排
  toggleDirection(){
    if(this.orderByDirection=='ASC'){
      this.orderByDirection='DESC';
    }
    else{
      this.orderByDirection='ASC';
    }
  }

  //順排逆排圖示
  getAscDescIcon(OrderField:string){
    let rc:string='';
    if(OrderField==this.orderByField){
      switch(this.orderByDirection){
        case 'ASC':
          rc='fa-angle-up';
          break;
        case 'DESC':
          rc='fa-angle-down';
          break;
      }
    }
    return rc;
  }
//排序相關結束

 

Html部分

準備好Service的相關程式碼後,接著就來處理Html的部分,主要有兩個部分:

  • 按下標題的排序動作
  • 排序後,要顯示『順排、逆排、無排序』的圖示

相關程式碼如下:

<table class="table table-bordered table-striped">
  <thead>
    <tr onmouseover="" style="cursor: pointer;">
      <th>功能</th>
      <th (click)="this.svcProd.SetOrderBy('ProductID');">
        ProductID 
        <i class="fa" [ngClass]="this.svcProd.getAscDescIcon('ProductID')"></i>
        <!-- <i class="fa fa-angle-up"></i> -->
      </th>
      <th (click)="this.svcProd.SetOrderBy('ProductName');">
        ProductName
        <i class="fa" [ngClass]="this.svcProd.getAscDescIcon('ProductName')" ></i>
      </th>
      <th (click)="this.svcProd.SetOrderBy('SupplierID');">
        SupplierID
        <i class="fa" [ngClass]="this.svcProd.getAscDescIcon('SupplierID')" ></i>
      </th>
      <th (click)="this.svcProd.SetOrderBy('CategoryID');">
        CategoryID
        <i class="fa" [ngClass]="this.svcProd.getAscDescIcon('CategoryID')" ></i>
      </th>
      <th (click)="this.svcProd.SetOrderBy('QuantityPerUnit');">
        QuantityPerUnit
        <i class="fa" [ngClass]="this.svcProd.getAscDescIcon('QuantityPerUnit')" ></i>
      </th>
      <th (click)="this.svcProd.SetOrderBy('UnitPrice');">
        UnitPrice
        <i class="fa" [ngClass]="this.svcProd.getAscDescIcon('UnitPrice')" ></i>
      </th>
      <th (click)="this.svcProd.SetOrderBy('UnitsInStock');">
        UnitsInStock
        <i class="fa" [ngClass]="this.svcProd.getAscDescIcon('UnitsInStock')" ></i>
      </th>
      <th (click)="this.svcProd.SetOrderBy('UnitsOnOrder');">
        UnitsOnOrder
        <i class="fa" [ngClass]="this.svcProd.getAscDescIcon('UnitsOnOrder')" ></i>
      </th>
      <th (click)="this.svcProd.SetOrderBy('ReorderLevel');">
        ReorderLevel
        <i class="fa" [ngClass]="this.svcProd.getAscDescIcon('ReorderLevel')"></i>
      </th>
      <th (click)="this.svcProd.SetOrderBy('Discontinued');">
        Discontinued
        <i class="fa" [ngClass]="this.svcProd.getAscDescIcon('Discontinued')" ></i>
      </th>
    </tr>
  </thead>
  <tbody>
    <tr *ngFor="let oItem of svcProd.datas">
      <td></td>
      <td>{{oItem.ProductID}}</td>
      <td>{{oItem.ProductName}}</td>
      <td>{{oItem.SupplierID}}</td>
      <td>{{oItem.CategoryID}}</td>
      <td>{{oItem.QuantityPerUnit}}</td>
      <td>{{oItem.UnitPrice}}</td>
      <td>{{oItem.UnitsInStock}}</td>
      <td>{{oItem.UnitsOnOrder}}</td>
      <td>{{oItem.ReorderLevel}}</td>
      <td>
        <input type="checkbox" [(ngModel)]="oItem.Discontinued">
      </td>
    </tr>
  </tbody>
</table>
<!--分頁開始-->
  <span><button (click)="svcProd.GetDatasByPage(1)">第一頁</button></span>
  <span *ngIf="(svcProd.startPg-10)>=1">
    <button (click)="svcProd.GetDatasByPage(svcProd.startPg-1)">...{{svcProd.startPg-1}}</button>
  </span>
  <span *ngFor="let pn of svcProd.pageNumArray">
    <button (click)="svcProd.GetDatasByPage(pn)" [ngClass]="{currentPage: pn==svcProd.currentPageNum}">{{pn}}</button>
  </span>
  <span *ngIf="svcProd.pageNumArrayMax < svcProd.totalPage">
    <button (click)="svcProd.GetDatasByPage(svcProd.pageNumArrayMax+1)">{{svcProd.pageNumArrayMax+1}}...</button>
  </span>
  <span><button (click)="svcProd.GetDatasByPage(svcProd.totalPage)">最後一頁</button></span>
  每頁筆數:
  <select name="sltPageSize" id="sltPageSize" [(ngModel)]="svcProd.pageSize" (change)="svcProd.GetDatasByPage(svcProd.currentPageNum)">
    <option value="5">5</option>
    <option value="10">10</option>
    <option value="15">15</option>
    <option value="20">20</option>
  </select>
  <!--分頁結束-->

其中,圖示的部分是使用「font aweson」,相關的套件的安裝與使用,請參考以下的連結

Angular 2 Font Aweson

 

執行結果:

在表頭的地方,游標移上去,游標變為「手」指標,讓使用者知道這部分可以按。按下後,會先順排(小到大),再按一次,從順排變逆排(大到小)。

末記

按下表頭,能夠針對點選的欄位,進行排序,這是基本的表格操作功能,搭配之前的分頁範例,小喵筆記一下,也提供大家參考。

^_^

 


以下是簽名:


Microsoft MVP
Visual Studio and Development Technologies
(2005~2019/6)