前端使用AngularJS的$resource,后端ASP.NET Web API,實現分頁、過濾


 

在上一篇中實現了增刪改查,本篇實現分頁和過濾。

本系列包括:

1、前端使用AngularJS的$resource,后端ASP.NET Web API,實現增刪改查
2、前端使用AngularJS的$resource,后端ASP.NET Web API,實現分頁、過濾


后端添加分頁、排序邏輯



首先要在后端API中添加分頁的邏輯。對於分頁來說,一般需要從前端獲取頁容量和當前頁變量,還可以獲取有關排序的變量。大致這樣:

 

public IHttpActionResult Get(int pageSize, int pageNumber, string orderBy = ""){}

 

在StudentsController這個控制器中,增加一個Get重載方法,用於接受分頁變量。

 

    [RoutePrefix("api/Students")]
    public class StudentsController : ApiController
    {
        private StudentsReop _reop = new StudentsReop();

        //GET api/Students
        public HttpResponseMessage Get()
        {
            var students = _reop.Query().ToList();
            return Request.CreateResponse(HttpStatusCode.OK, students);
        }

        //GET api/Students/5
        public HttpResponseMessage Get(int id)
        {
            var student = _reop.Get(id);
            return Request.CreateResponse(HttpStatusCode.OK, student);
        }

        //GET api/Students/pageSize/pageNumber/orderBy(optional)
        [Route("{pageSize:int}/{pageNumber:int}/{orderBy:alpha?}")]
        public IHttpActionResult Get(int pageSize, int pageNumber, string orderBy = "")
        {
            var totalCount = _reop.Query().ToList().Count();//總數量
            var totalPages = Math.Ceiling((double)totalCount/pageSize);//總頁數和pageSize有關
            var tempResult = _reop.Query();

            if (QueryHelper.PropertyExists<StudentVm>(orderBy))
            {
                var orderByExpression = QueryHelper.GetPropertyExpression<StudentVm>(orderBy);
                tempResult = tempResult.AsQueryable().OrderBy(orderByExpression);
            }
            else
            {
                tempResult = tempResult.OrderBy(c => c.Id);
            }

            var students = tempResult.Skip((pageNumber - 1) * pageSize)
                    .Take(pageSize)
                    .ToList();

            var result = new
            {
                TotalCount = totalCount,
                TotalPages = totalPages,
                Students = students
            };

            return Ok(result);

        }


        //POST api/Students
        public void Post([FromBody]StudentVm student)
        {
            _reop.Post(student);
        }


        //PUT api/Students/5
        public void Put(int id, [FromBody]StudentVm student)
        {
            _reop.Put(id, student);
        }


        //DELETE api/Students
        public void Delete(int id)
        {
            _reop.Delete(id);
        }
    }

 

以上,Get(int pageSize, int pageNumber, string orderBy = "")方法中,首先獲取排序后的臨時數據,再使用skip,take方法獲取分頁數據,最后返回給前端一個json數據,其中,TotalCount表示總數據量,Students表示當前頁下的數據,這2個字段供前端讀取。另外,QueryHelper封裝了可以根據模型字段獲取表達式樹的方法。

 

    internal static class QueryHelper
    {
        public static bool PropertyExists<T>(string propertyName)
        {
            return typeof(T).GetProperty(propertyName, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance) != null;
        }

        public static Expression<Func<T, string>> GetPropertyExpression<T>(string propertyName)
        {
            if (typeof(T).GetProperty(propertyName, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance) == null)
            {
                return null;
            }

            var paramterExpression = Expression.Parameter(typeof(T));

            return (Expression<Func<T, string>>)Expression.Lambda(Expression.PropertyOrField(paramterExpression, propertyName), paramterExpression);
        }

        public static Expression<Func<T, int>> GetPropertyExpressionInt<T>(string propertyName)
        {
            if (typeof(T).GetProperty(propertyName, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance) == null)
            {
                return null;
            }

            var paramterExpression = Expression.Parameter(typeof(T));

            return (Expression<Func<T, int>>)Expression.Lambda(Expression.PropertyOrField(paramterExpression, propertyName), paramterExpression);
        }
    }
    

 

此時,通過瀏覽器可以獲取到分頁數據。比如:http://localhost:49621/api/Students/5/2/Name

前端准備



前端需要用到Michael Bromley寫的一個分頁Directive。 通過如下可安裝:

bower install angular-utils-pagination

npm install angular-utils-pagination

還需要安裝bootstrap和jquery:

npm install bootstrap
npm install jquery

文件結構變為:

app.js 主module,路由都在這里配置
index.html 主視圖,引用所有的css,js文件,提供讓其它部分視圖呈現的一塊區域<div ng-view></div>
.....service/ 自定義服務,$resouce的核心就封裝在這里
..........studentService.js
.....controller/
..........studentsCtrl.js 列表
..........studentUpdateCtrl.js 更新
..........studentCreateCtrl.js 添加
.....views/
..........Students.html 列表
..........StudentInfo.html 更新
..........StudentCreate.html 添加
vendor/
......diaPagination/  Michael Bromley寫的directive
..........dirPagination.css
..........dirPagination.js
..........dirPagination.tpl.html

 

index.html



相對於上一篇,添加了如下:

<link rel="stylesheet" href="node_modules/bootstrap/dist/css/bootstrap.min.css"/>
<link rel="stylesheet" href="vendor/dirPagination/dirPagination.css"/>

<script src="node_modules/jquery/dist/jquery.min.js"></script>
<script src="node_modules/bootstrap/dist/js/bootstrap.min.js"></script>
<script src="vendor/dirPagination/dirPagination.js"></script>

並使用上了bootstrap。

 

<!DOCTYPE html>
<html lang="en" ng-app="studentManagement">
<head>
  <meta charset="UTF-8">
  <title>{{title}}</title>
  <link rel="stylesheet" href="node_modules/alertify/themes/alertify.core.css"/>
  <link rel="stylesheet" href="node_modules/bootstrap/dist/css/bootstrap.min.css"/>
  <link rel="stylesheet" href="vendor/dirPagination/dirPagination.css"/>
</head>
<body>
  <div>
    <p>
      <a href="#/">Students</a>
      &nbsp;&nbsp;
      <a href="#/Create">Create Student</a>
    </p>
  </div>

  <div class="container">
    <div class="row">
      <div class="col-lg-8">
        <div ng-view></div>
      </div>
    </div>
  </div>



  <script src="node_modules/angular/angular.min.js"></script>
  <script src="node_modules/angular-route/angular-route.min.js"></script>
  <script src="node_modules/angular-resource/angular-resource.min.js"></script>
  <script src="node_modules/angular-cookies/angular-cookies.min.js"></script>
  <script src="node_modules/alertify/lib/alertify.min.js"></script>
  <script src="node_modules/jquery/dist/jquery.min.js"></script>
  <script src="node_modules/bootstrap/dist/js/bootstrap.min.js"></script>

  <script src="app.js"></script>

  <script src="service/studentService.js"></script>
  <script src="controller/studentUpdateCtrl.js"></script>
  <script src="controller/studentsCtrl.js"></script>
  <script src="controller/studentCreateCtrl.js"></script>
  <script src="vendor/dirPagination/dirPagination.js"></script>


</body>
</html>

 

app.js



對比上一篇,這里添加了對angularUtils.directives.dirPagination這個module的依賴,去掉了/這個路由中有關resolve獲取數據的機制,因為現在要分頁了,每次都要獲取數據,而不是把所有數據先從服務端獲取到放到路由中。

 

"use strict";

var studentsManagement = angular.module("studentManagement",["ngResource","ngCookies","ngRoute","angularUtils.directives.dirPagination"])
    .run(function($rootScope){
        $rootScope.title = "Home";
    })
    .config(["$routeProvider","$locationProvider", function($routeProvider, $locationProvider){

        //在全局配置分頁模板 需要注入paginationTemplateProvider
        //paginationTemplateProvider.setPath('path/to/dirPagination.tpl.html');

        //關於url的基本配置
        //$locationProvider.html5Mode({
        //    enabled: true,
        //    requireBase: false
        //});

        //配置路由
        $routeProvider.when("/", {
            templateUrl: "views/Students.html",
            controller: "studentsCtrl"
            //resolve: {
            //    students: function($q,studentDataService){
            //
            //        var queryArgs = {
            //            pageSize: 3,
            //            pageNumber: 1,
            //            orderBy: "id"
            //        };
            //
            //        //$q異步執行方法
            //        var deferred = $q.defer();
            //        studentDataService.query(function(data){
            //            deferred.resolve(data);
            //        });
            //
            //        return deferred.promise;
            //    }
            //}
        }).when("/Student/:id",{
            templateUrl: "views/StudentInfo.html",
            controller: "studentUpdateCtrl",
            resolve: {
                student: function($q, studentDataService, $route){
                    var defered = $q.defer();

                    //從路由中獲取id的值
                    var id = $route.current.params.id;

                    studentDataService.get({id: id}, function(data){
                        defered.resolve(data);
                    });

                    return defered.promise;
                }
            }
        }).when("/Create",{
            templateUrl: "views/CreateStudent.html",
            controller: "studentCreateCtrl"
        });

    }]);
    

 

 

以上,我們還可以通過paginationTemplateProvider.setPath('path/to/dirPagination.tpl.html');在全局中配置分頁模板,但這里沒有。

studentService.js



用$resouce封裝請求數據這塊有變化,因為要帶上分頁、排序參數。

 

angular.module('studentManagement').factory("studentDataService",["$resource", function($resource){

    var baseUrl = "http://localhost:49621/api/Students";
    return $resource("http://localhost:49621/api/Students",{},{
        query: {
            method: "GET",
            url: baseUrl + "/:pageSize/:pageNumber/:orderBy",
            params: {pageSize: '@pageSize', pageNumber: '@pageNumber', orderBy: '@orderBy'}
        },
        //query: {
        //    method: "GET",
        //    isArray: true,
        //},
        create: {method: "POST"},
        get: {method: "GET", url: baseUrl + "?id=:id"},
        remove: {method: "DELETE", url: baseUrl + "?id=:id"},
        update: {method: "PUT", url: baseUrl + "?id=:id"}
    })
}]);

 

studentsControl.js

 

 

angular.module('studentManagement').controller("studentsCtrl", ['$scope', '$route', '$rootScope', 'studentDataService', function ($scope, $route, $rootScope, studentDataService) {

    $scope.students = [];
    $scope.total = 0; //總數據條數
    $scope.currentPage = 1;
    $scope.pageSize = 3; //頁容量

    //初次加載
    getPageStudents(1);


    $scope.pageChangeHandler = function (num) {
        getPageStudents(num);
    };

    //獲取分頁數據
    function getPageStudents(pageNumber){
        var queryArgs = {
            pageSize: $scope.pageSize,
            pageNumber: pageNumber,
            orderBy: 'name'
        };

        studentDataService.query(queryArgs).$promise.then(function(result){
            $scope.students = result.students;
            $scope.total = result.totalCount;
        }, function(result){ //如果失敗
            console.log('fail');

        });
    }

    $rootScope.title = "Students";

    //$scope.students = $route.current.locals.students;//students在路由resolve中定義

    //刪除
    $scope.removeStudent = function (id, student) {
        studentDataService.remove({id: id}).$promise.then(function () {
            //獲取student在當前集合中的索引
            var index = $scope.students.indexOf(student);
            $scope.students.splice(index, 1);
            alertify.log(student.Name + ' is removed');
        });
    };

}]);
    //.controller("OtherController", ["$scope", function ($scope) {
    //    $scope.pageChangeHandler = function (num) {
    //        console.log('going to page ' + num);
    //    };
    //}]);

 

以上,初次加載以及點擊分頁按鈕的時候都觸發getPageStudents方法,傳入頁容量和當前頁變量。


Students.html



在dir-paginate中多了一個total-items屬性,把從controller中獲取到的total變量值賦值給它。

 

 

<!--顯示內容的控制器-->
<div class="my-controller">


  <div class="row">
    <div class="col-xs-4">
      <h3>當前頁: {{ currentPage }}</h3>
    </div>
    <div class="col-xs-4">
      <label for="search">搜索:</label>
      <input ng-model="q" id="search" class="form-control" placeholder="Filter text">
    </div>
    <div class="col-xs-4">
      <label for="search">每頁條數:</label>
      <input type="number" min="1" max="100" class="form-control" ng-model="pageSize">
    </div>
  </div>
  <br>
  <div class="panel panel-default">
    <div class="panel-body">

      <table>
        <thead>
          <tr>
            <th>Name</th><th>Age</th><th>Actions</th>
          </tr>
        </thead>
        <tbody>
         <!--itemsPerPage是必須的,要放在所有過濾的最后面,表示頁容量-->
         <!--dir-paginate的pagination-id屬性,可選,和dir-pagination-controls中的pagination-id對應-->
         <!--dir-paginate的current-page屬性,可選,默認會讀取$scope中的_currentPage字段-->
         <!--dir-paginate的total-items屬性,可選,用來讀取服務端數據,先把總頁數顯示出來-->
          <tr dir-paginate="student in students | filter:q | itemsPerPage: pageSize" total-items="total" current-page="currentPage">
            <td>{{student.name}}</td>
            <td>{{student.age}}</td>
            <td>
              <a href="#/Student/{{student.Id}}">更新</a>
              &nbsp;&nbsp;
              <a href="javascript:void(0)" ng-click="$parent.removeStudent(student.Id, student)">移除</a>
            </td>
          </tr>
        </tbody>
      </table>

    </div>
  </div>
</div>

<!--顯示分頁的控制器-->
<!--<div ng-controller="OtherController" class="other-controller">-->
<div class="other-controller">
  <div class="text-center">
    <!--其它屬性包括:max-size, direction-links,boundary-links,pagination-id,auto-hide-->
    <!--max-size:可選,默認為最大是9,最小是5-->
    <!--direction-links:可選,默認true,決定是否顯示向前向后按鈕-->
    <!--boundary-links,可選,默認false,決定是否顯示首頁和最后一頁按鈕-->
    <!--on-page-change,可選,默認為null,聲明當點擊頁數按鈕后的回調函數,一旦聲明,必須傳入newPageNumber形參,必須在$scope中聲明回調函數,比如這里的pageCHnageHandler函數-->
    <!--pagination-id,可選,與dir-paginate中的pagination-id值對應-->
    <!--template-url,可選,默認值是directives/pagination/dirPagination.tpl.html,也可以在全局config中,通過paginationTemplateProvider配置-->
    <!--auto-hide,可選,默認是true,決定當沒有足夠的分頁數據時,分頁是否顯示-->
    <!--這里的dir-pagination-controls不能離開dir-paginate而單獨存在,否則報錯-->
    <dir-pagination-controls boundary-links="true" on-page-change="pageChangeHandler(newPageNumber)" template-url="vendor/dirPagination/dirPagination.tpl.html"></dir-pagination-controls>
  </div>
</div>

 

本系列結束☺


參考資料:

有關Web API配合AngularJS分頁:

● https://code.msdn.microsoft.com/AngularJS-with-Web-API-43e5de16

有關AngularJS分頁的Directive:

● http://www.michaelbromley.co.uk/blog/108/paginate-almost-anything-in-angularjs
● https://github.com/michaelbromley/angularUtils/tree/master/src/directives/pagination#working-with-asynchronous-data

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM