【问题标题】:how do I make searching/pagination reusable in my application?如何在我的应用程序中使搜索/分页可重用?
【发布时间】:2016-04-29 04:19:36
【问题描述】:

我们决定在我们的应用程序中使用服务器端分页。实现很简单:

  • 假设我们在服务器端有这样一个搜索动作:

    [HttpGet]
    public ActionResult GetPeopleByName(String term, Int32 itemsPerPage = 10, Int32 page = 0) {
        var matches = this.people.Where(i => i.Name.Contains(term));
        return Json(
            data: new {
                people = matches.Skip(itemsPerPage * page).Take(itemsPerPage).OrderBy(i => i.Name),
                total = matches.Count()
            },
            behavior: JsonRequestBehavior.AllowGet
        );
    }
    
  • 在客户端我们有一个subscriptionHolderController:

    app.controller('subscriptionHolderController', ['$scope', '$http', function($scope, $http) {
        $scope.matches = [];
        $scope.itemsPerPage = 5;
        $scope.currentPage = 0;
        $scope.searchTerm = '';
    
        // $scope.prevPage = function() { ... };
        // $scope.prevPageDisabled = function() { ... };
        // $scope.nextPage = function() { ... };
        // $scope.nextPageDisabled = function() { ... };
    
        $scope.pageCount = function() { 
            return Math.ceil($scope.totalPages / $scope.itemsPerPage); 
        };
    
        $scope.$watch('currentPage', function() { $scope.search(); });
    
        $scope.search = function() {
            if($scope.searchTerm === '') return;
            // initiate a GET-request with params: { page: $scope.currentPage, term: $scope.searchTerm, itemsPerPage: $scope.itemsPerPage }
        }
        $scope.matchesFound = function () { return $scope.matches.length > 0; }
    }]);
    

问题

因此我们有一个简单的search-box。但我们的应用程序需要一种具有一些附加功能的搜索类型,它不使用搜索词,其结果集应该以与上面所示相同的方式分页

如何为不同类型的搜索重用分页逻辑?

【问题讨论】:

  • 一个想法是将分页逻辑+ UI分离为具有隔离范围的指令。这将使您能够在多个地方使用它。看看指令部分[docs.angularjs.org/guide/directive] 在角度文档中。
  • 您是否有兴趣重用客户端或服务器端?
  • @DaveA 我想按部分/页面从服务器获取数据,无论它是输入(在客户端),您发送的是 search termpage info 还是 @ 987654329@ 一定会说 radioboxes 而你正在发送 page info + that parameters
  • @CMR 你能说明我如何制定这样的指令吗?
  • 一个快速的解决方案是使用类似这样的东西 > angular-ui.github.io/bootstrap/#/pagination 。你从你的控制器提供参数,你就完成了。如果这对您不起作用,您必须选择自定义寻呼机指令。让我知道这是否是您想要走的路线,我们可以进一步讨论,也许构建一个 jsFiddle 作为示例。

标签: c# javascript angularjs pagination


【解决方案1】:

在服务器端,您可以返回一个通用类,用于保存您的数据,即总行数。

public class PagedResult<T>
    {
        public PagedResult(IEnumerable<T> data, long total)
        {
            Data = data;
            Total = total;
        }
        public PagedResult()
        {
        }
        public IEnumerable<T> Data { get; set; }
        public long Total { get; set; }

    }

您还可以抽象任何函数的输入参数,例如:

public class PageInfo
    {

        public int Page { get; set; }           
        public int PageSize { get; set; }
        public int Skip
        {
            get
            {
                return PageSize*(Page - 1);
            }
        }

        public PageInfo(int page, int pageSize)
        {
            Page = page;
            PageSize = pageSize;
        }

    }

一个实际的例子可能是这样的:

[HttpGet]
public ActionResult GetPeopleByName(String term, PageInfo pageinfo) {
    var matches = this.people.Where(i => i.Name.Contains(term));

    var pagedResult =  new PagedResult<AnySearchType>{
            data = matches.Skip(pageinfo.skip).Take(pageinfo.size).OrderBy(i => i.Name),
            total = matches.Count()
        };

    return Json(
        data: pagedResult,
        behavior: JsonRequestBehavior.AllowGet
    );
}

在客户端,您可以使用指令通过传递以下参数来抽象分页逻辑:

查看

<div class="box-content" scroll-pager="pagerConfig">
your data
<div>

控制者:

您可以传递一些配置,例如:

$scope.pagerConfig = {
        pageSize: 10,
        data: 'model.Data', // some text reference to your model
        total: 'model.Total', // some text reference to your model
        currentPage: 1,
        searchParamName: 'Text',// some text reference to your model
        resource: projectResource,// pass a resource object
        success: function (data, page, total) {

            }
    };

【讨论】:

    【解决方案2】:

    为分页创建单独的类。在此类中,您可以定义分页方法,您可以将分页应用于任何类型,并且使用不同的参数,您还可以自定义应用分页和页面大小的字段。

    【讨论】:

      【解决方案3】:

      这就是我最终的结果:

      app.directive('pager', function() {
          return {
              restrict: 'EA',
              scope: {
                  onChange: '&',
                  items: '=',
                  itemsPerPage: '@'
              },
              replace: true,
              templateUrl: '/scripts/js/app/pager.html',
              link: function(scope, el, attrs) {
                  scope.currentPage = 1;
      
                  scope.isFirstPage = function() {
                      return scope.currentPage === 1;
                  }
      
                  scope.decPage = function() {
                      if(scope.currentPage > 1) --scope.currentPage;
                  }
      
                  scope.isLastPage = function() {
                      return scope.currentPage >= scope.totalPages();
                  }
      
                  scope.totalPages = function() {
                      return Math.ceil(scope.items.total / scope.itemsPerPage);
                  }
      
                  scope.incPage = function() {
                      if(!scope.isLastPage()) ++scope.currentPage;
                  }
      
                  scope.$watch("currentPage", function(value) {
                      scope.onChange({page: value, itemsPerPage: scope.itemsPerPage});
                  });
              }
          };
      });
      

      标记

      <div id="content" ng-app="subscriptionsManager">
          <div ng-controller="subscriptionHolderController">
              <div class="row">
                  <div class="columns medium-6 large-6">
                      <div class="searchbar">
                          <div class="searchbar-inner">
                              <input ng-model="searchTerm" type="text" />
                              <button ng-click="search(1, 35)" class="tiny">search</button>
                          </div>
                      </div>
                  <div pager items-per-page="35" items="data" on-change="respondToTheChange(page, itemsPerPage)"></div>
                 </div>
                 <div class="columns medium-6 large-6">
                      <div class="button-group filter-sample">
                           <button ng-click="toggleState1()" ng-class="{true: 'selected', false: 'secondary'}[state1]" class="tiny">filter1</button>
                           <button ng-click="toggleState2()" ng-class="{true: 'selected', false: 'secondary'}[state2]" class="tiny">filter2</button>
                           <button ng-click="toggleState3()" ng-class="{true: 'selected', false: 'secondary'}[state3]" class="tiny">filter3</button>
                           <button ng-click="search2(1, 35)" class="tiny">search</button>
                      </div>
                      <div pager items-per-page="35" items="data2" on-change="respondToTheChange2(page, itemsPerPage)"></div>
                   </div>
              </div>
          </div>
      </div>    
      

      控制器

      // search using a search term
      
      $scope.data = { items: [], total: 0 };
      $scope.searchTerm = '';
      
      $scope.state1 = false;
      $scope.state2 = false;
      $scope.state3 = false;
      
      $scope.toggleState1 = function() {
          $scope.state1 = !$scope.state1;
      }
      
      $scope.toggleState2 = function() {
          $scope.state2 = !$scope.state2;
      }
      
      $scope.toggleState3 = function() {
          $scope.state3 = !$scope.state3;
      }
      
      $scope.search = function(page, itemsPerPage) {
          if($scope.searchTerm === '') return;
          if(!angular.isDefined(page) || page == null) page = 1;
          if(!angular.isDefined(itemsPerPage) || itemsPerPage == null) itemsPerPage = 35;
      
          $http({
              url: '/subscriptions/GetSubscribersByNamePaged',
              method: 'GET',
              params: { term: $scope.searchTerm, page: page, itemsPerPage: itemsPerPage }
          })
          .success(function(data, status, headers, config) {
              $scope.data = data;
          }).error(function(data, status, headers, config) {
              console.log('error: ' + data);
          });
      }
      
      // search using anything else
      
      $scope.search2 = function(page, itemsPerPage) {
          if(!angular.isDefined(page) || page == null) page = 1;
          if(!angular.isDefined(itemsPerPage) || itemsPerPage == null) itemsPerPage = 35;
      
          $http({
              url: '/subscriptions/GetSubscribersByFilters',
              method: 'GET',
              params: { state1: $scope.state1, state2: $scope.state2, state3: $scope.state3, page: page, itemsPerPage: itemsPerPage }
          })
          .success(function(data, status, headers, config) {
              $scope.data2 = data;
          }).error(function(data, status, headers, config) {
              console.log('error: ' + data);
          });
      }
      
      // bind searches!
      
      $scope.respondToTheChange = function(page, itemsPerPage) {
          $scope.search(page, itemsPerPage);
      }
      
      $scope.respondToTheChange2 = function(page, itemsPerPage) {
          $scope.search2(page, itemsPerPage);
      }
      

      【讨论】:

        猜你喜欢
        • 2020-05-18
        • 1970-01-01
        • 1970-01-01
        • 2021-08-16
        • 1970-01-01
        • 1970-01-01
        • 2012-02-03
        • 2022-12-21
        • 1970-01-01
        相关资源
        最近更新 更多