Question

I want to provide a page selection directive that generates "Page [ 1 ] of x". The number of pages in the dropdown is dependent upon values passed into the directive, so it can't be part of a static template. I'm having a difficult time figuring out how/where to generate the <select><option>...</select>.

I have tried, unsuccessfully, to do it via:

  • an $observe (and $watch) in link
  • a function added to $scope in controller, which returns $compile(markup)($scope) (This gives the error Error: [$parse:isecdom] Referencing DOM nodes in Angular expressions is disallowed!)
  • a sub-directive for the <select> element (The link $observer never seemed to get the recordCount updates, regardless of inherited or shared scope.)
  • ng-repeat in the template

Here's my mangled code, as it currently stands.

HTML

<x-pager
  record-count="{{recordCount}}"
  page-size="pageSize"
  page-number="pageNumber"
  set-page="selectPage(page)"
></x-pager>

JS

module.directive("pager", ["$compile",
    function ($compile)
    {
        return {
            template:   "<div class='pager' ng-show='recordCount > pageSize'>\
                           {{recordCount}} results\
                           <button>&laquo; Prev</button>\
                           page <select>\
                           <option>#</option>\
                           </select> of {{calcPages()}}\
                           <button>Next &raquo;</button>\
                         </div>",
            replace:    true,
            restrict:   "E",
            scope:      {
                recordCount: "@",
                pageSize:    "=",
                pageNumber:  "=",
                setPage:     "&"
            },
            link: function (scope, element, attrs)
            {
                /*
                 * We can't build the page selection dropdown until
                 * we know how many records we have. Register an
                 * observer to do this when recordCount changes.
                 */
                attrs.$observe("recordCount", function (recCnt)
                {
                    var html;
                    var pages;
                    var i;

                    if (angular.isDefined(recCnt)) {
                        html  = "<select>\n";
                        pages = Math.ceil(scope.recordCount / scope.pageSize);

                        for (i=1; i<=pages; i++) {
                            html += "  <option value='" + i + "'>" + i + "</option>\n";
                        }
                        html += "</select>";
                        console.log("generatePageSelect html", html);

                        html = $compile(html)(scope);

                        // add the template content
//                      angular.element("select.page-selector").html(html);
// template:            page <select class='page-selector'></select> of {{calcPages()}}\
                    }
                });
            },
            controller: function ($scope)
            {
                $scope.calcPages = function ()
                {
                    return Math.ceil($scope.recordCount / $scope.pageSize);
                };

                function genPagesArray ()
                {
                    var pages = $scope.calcPages();
                    var i;
                    var pagesArray = [];

                    for (i=0; i<pages; i++) {
                        pagesArray.push(i);
                    }

                    return pagesArray;
                }
                $scope.pagesArray = genPagesArray();
                console.log("$scope.pagesArray", $scope.pagesArray);


// template:    page {{generatePageSelect()}} of {{calcPages()}}\
                $scope.generatePageSelect = function ()
                {
                    var html  = "<select>\n";
                    var pages = $scope.calcPages();
                    var i;

                    for (i=1; i<=pages; i++) {
                        html += "  <option value='" + i + "'>" + i + "</option>\n";
                    }
                    html += "</select>";

                    return $compile(html)($scope);
                };
            }
        };
    }
]);
Était-ce utile?

La solution

To expand on my comment from earlier, here's a directive that does (most of) what you want it to do.

angular.module('Test', []).controller('TestCtrl', function($scope) {
  $scope.pageSize = 10;
  $scope.pageNumber = 1;
  $scope.recordCount = 30;
}).directive("pager", function () {
  return {
    template: '<div class="pager" ng-show="recordCount > pageSize">\
      {{recordCount}} results\
      <button ng-click="pageNumber = pageNumber - 1" ng-disabled="pageNumber <= 1">&laquo; Prev</button>\
      page <select ng-model="pageNumber" ng-options="i for i in pages"></select> of {{totalPages}}\
      <button ng-click="pageNumber = pageNumber + 1" ng-disabled="pageNumber >= totalPages">Next &raquo;</button>\
    </div>',
    replace: true,
    restrict: "E",
    scope:      {
      recordCount: "@",
      pageSize:    "=",
      pageNumber:  "=",
      setPage:     "&"
    },
    link: function (scope, element, attrs) {
      attrs.$observe("recordCount", function (count) {
        if (angular.isDefined(count)) {
          scope.recordCount = parseInt(count);
          var i;
          scope.totalPages = Math.ceil(scope.recordCount / scope.pageSize);

          scope.pages = [];
          for (i=1; i<=scope.totalPages; i++) {
            scope.pages.push(i);
          }
        }
      });
    }
  }
});

Plunkr here.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top