具有隔离范围的AngularJS分页指令

时间:2014-03-31 16:38:41

标签: angularjs pagination angularjs-directive

我的团队成员写了以下分页指令:

myApp.directive('pagination', function($timeout) {
    return {
        restrict: 'A',
        controller: function($scope, $element, $attrs, $rootScope) {
            var halfDisplayed = 1.5,
                    displayedPages = 3,
                    edges = 2;
            $scope.getInterval = function() {
                return {
                    start: Math.ceil($scope.currentPage > halfDisplayed ? Math.max(Math.min($scope.currentPage - halfDisplayed, ($scope.pages - displayedPages)), 0) : 0),
                    end: Math.ceil($scope.currentPage > halfDisplayed ? Math.min($scope.currentPage + halfDisplayed, $scope.pages) : Math.min(displayedPages, $scope.pages))
                };
            };
            $scope.selectPage = function(pageIndex) {
                $scope.currentPage = pageIndex;
                $scope.$apply();
                $scope.draw();
                $scope.paginationUpdate();
            };
            $scope.appendItem = function(pageIndex, opts) {
                var options, link;

                pageIndex = pageIndex < 0 ? 0 : (pageIndex < $scope.pages ? pageIndex : $scope.pages - 1);

                options = $.extend({
                    text: pageIndex + 1,
                    classes: ''
                }, opts || {});

                if (pageIndex === $scope.currentPage) {
                    link = $('<span class="current">' + (options.text) + '</span>');
                } else {
                    link = $('<a href="javascript:void(0)" class="page-link">' + (options.text) + '</a>');
                    link.bind('click', function() {
                        $scope.selectPage(pageIndex);
                    });
                }

                if (options.classes) {
                    link.addClass(options.classes);
                }

                $element.append(link);
            };
            $rootScope.draw = function() {
                $($element).empty();
                var interval = $scope.getInterval(),
                        i;

                // Generate Prev link
                if (true) {
                    $scope.appendItem($scope.currentPage - 1, {
                        text: 'Prev',
                        classes: 'prev'
                    });
                }

                // Generate start edges
                if (interval.start > 0 && edges > 0) {
                    var end = Math.min(edges, interval.start);
                    for (i = 0; i < end; i++) {
                        $scope.appendItem(i);
                    }
                    if (edges < interval.start) {
                        $element.append('<span class="ellipse">...</span>');
                    }
                }

                // Generate interval links
                for (i = interval.start; i < interval.end; i++) {
                    $scope.appendItem(i);
                }

                // Generate end edges
                if (interval.end < $scope.pages && edges > 0) {
                    if ($scope.pages - edges > interval.end) {
                        $element.append('<span class="ellipse">...</span>');
                    }
                    var begin = Math.max($scope.pages - edges, interval.end);
                    for (i = begin; i < $scope.pages; i++) {
                        $scope.appendItem(i);
                    }
                }

                // Generate Next link
                if (true) {
                    $scope.appendItem($scope.currentPage + 1, {
                        text: 'Next',
                        classes: 'next'
                    });
                }
            };
        },
        link: function(scope, element, attrs, controller) {
            $timeout(function() {
                scope.draw();
            }, 2000);
            scope.$watch(scope.paginatePages, function() {
                scope.draw();
            });
        },
        template: '<div class="pagination-holder dark-theme">' + '</div>',
        replace: true
    };
});

不幸的是,当他写这篇文章时,该指令引用了控制器变量和函数:

function PatientListModalConfigCtrl($scope, $rootScope, myService) {
    $scope.currentPage = 0;
    $scope.paginationUpdate = function() {
        var list = myService.search($scope.currentPage + 1);
        list.then(function(data) {
            $rootScope.List = data[1];
            $rootScope.pages = data[0];
        });
    };
};

我能够使用attr参数用$scope[]();替换函数调用,但是一旦我尝试添加:

scope: {
    currentPage: '=',
    totalPages: '='
}

进入指令并将指令与控制器隔离,分页停止显示。我也可以为这两个变量使用attr参数吗?我更喜欢在指令中使用范围,因为变量会发生变化,但我的尝试失败了。我将不胜感激任何反馈。

1 个答案:

答案 0 :(得分:1)

不幸的是,我不得不说整个指令设计得有点糟糕。 $ rootScope的依赖性是一个很大的代码气味,所以在控制器中注入了所有HTML。

要获得主题,您将双向绑定到基元(整数)。我不完全确定这是你的整个问题,但它不会像你期望的那样工作。一旦你想到它,它是非常合乎逻辑的,AngularJS怎么能把任何数据放回(即更新)一个原语?

从它的角度来看,你实际上并不想要双向绑定,你只需要发送一些值。对于这样的简单数据,您可以将它们定义为属性('@'),然后使用attrs。$ observe()来监听更改。至于HTML,您可以使用current-page="{{currentPage}}"传递值(请注意,它将作为一个字符串,然后您可以解析它)。

另一种选择可能是传入一个对象(使用双向绑定)。例如:

page = {
    currentPage: 3,
    totalPages: 14
}