【问题标题】:AngularJS Pagination Directive w/ Isolate ScopeAngularJS 分页指令 w/ 隔离范围
【发布时间】:2014-04-02 05:59:26
【问题描述】:

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

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 参数吗?我更喜欢在指令中使用范围,因为变量会发生变化,但我的尝试失败了。如有任何反馈,我将不胜感激。

【问题讨论】:

  • 您是否调整了 HTML 中的指令以将值也传递给作用域?
  • 是的,我在指令中声明的范围内使用了以下内容,但仍然失败。 &lt;div pagination="paginationUpdate();" current-page="currentPage" total-pages="pages" style="float: right;"&gt;&lt;/div&gt;

标签: angularjs pagination angularjs-directive


【解决方案1】:

不幸的是,我不得不说整个指令看起来设计得有点糟糕。对 $rootScope 的依赖是一种很大的代码味道,所有在控制器中注入 HTML 也是如此。

要进入主题,您需要对原语(整数)进行双向绑定。我不完全确定这是你的全部问题,但它不会像你期望的那样工作。仔细想想,这很合乎逻辑,AngularJS 怎么能将任何数据放回(即更新)原语?

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

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

page = {
    currentPage: 3,
    totalPages: 14
}

【讨论】:

  • 我同意,我真的不喜欢团队负责人像他那样选择使用 $rootScope。传递对象不起作用,但传递值和 attrs.$observe() 可以使分页显示和运行。不过,您对如何在指令之外更新当前页面有任何建议吗? $scope.selectPage 函数最初在控制器中设置值,我的服务需要更新此值才能工作。
  • 我不确定你在指令之外更新当前页面是什么意思,但是我还没有真正研究好代码,而且到处乱扔的所有 HTML 都很难.也就是说,指令不应该向外工作,它们只能向内工作。因此,您定义了一个模板,该指令仅对该模板负责。您可以向其中添加或删除内容,但外部应该是禁区。因此,您需要在足够高的级别定义指令,以使其涵盖所有内容。没有要求很难给出好的建议。
  • 我通过在指令中放置一个 $emit 并在控制器中放置一个 $on 监听器来让它工作。我不认为它一定是一个理想的解决方案,但考虑到原始指令有多糟糕,我很高兴该指令现在可以像它一样重用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-12-08
  • 1970-01-01
  • 2012-12-27
  • 2019-10-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多