将功能从控制器分离到指令

时间:2014-05-23 11:56:58

标签: angularjs angularjs-directive angularjs-scope angularjs-ng-repeat

我知道Angular控制器应该尽量不执行繁重的逻辑计算。

我的控制器中有一个函数可以获取当月的12个月的列表:

app.controller("MyController", function($scope) {

    $scope.getLast12Months = function () {

        var date = new Date();
        var months = [],
            monthNames = [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ];
        for(var i = 0; i < 12; i++) {
            months.push(monthNames[date.getMonth()] + ' ' + date.getFullYear());

            // Subtract a month each time
            date.setMonth(date.getMonth() - 1);
        }
        $scope.months = months;

        return months;
    }


});

通过以下方式显示在我的HTML中:

<th ng-repeat="months in getLast12Months()">{[{ months }]}</th>

我已尝试通过以下方式将其纳入指令:

app.directive("ngGetLast12Months", function () {
return function ($scope) {

var date = new Date();
     var months = [],
            monthNames = [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ];
        for(var i = 0; i < 12; i++) {
            months.push(monthNames[date.getMonth()] + ' ' + date.getFullYear());

            // Subtract a month each time
            date.setMonth(date.getMonth() - 1);
        }
        $scope.months = months;

        return months;
    }
});

在HTML中:

<th ng-get-last-12-months>{[{ months }]}</th>

我可以看到我的指令是通过console.log触发的,但输出显示为:

[“2014年5月”,“2014年4月”,“2014年3月”,“2014年2月”,“2014年1月”,“2013年12月”,“2013年11月”,“2013年10月”,“2013年9月”,“ 2013年8月“,”2013年7月“,”2013年6月“]

而不是ng-repeat时尚显示为:

2014年5月2014年2014年3月2014年2月2014年1月2014年12月2013年11月2013年10月2013年9月2013年8月2013年7月2013年6月2013年


更新基于工程师的示例

但是看到:错误:[$ compile:tplrt] errors.angularjs.org/1.2.8/$compile /...

app.directive('ngGetLast12Months', function () {
return {
  replace: true,
  restrict: 'EA',
  template: '<th ng-repeat="month in months">{[{ month }]}</th>',
  link: function ($scope) {
    var date = new Date();
    var months = [], monthNames = [
        'Jan',
        'Feb',
        'Mar',
        'Apr',
        'May',
        'Jun',
        'Jul',
        'Aug',
        'Sep',
        'Oct',
        'Nov',
        'Dec'
      ];
    for (var i = 0; i < 12; i++) {
      months.push(monthNames[date.getMonth()] + ' ' + date.getFullYear());
      // Subtract a month each time
      date.setMonth(date.getMonth() - 1);
    }
    $scope.months = months;
    return months;
  }
};
});

3 个答案:

答案 0 :(得分:1)

像这样创建指令:

app.directive("ngGetLast12Months", function () {
    return {
        replace : true,
        restrict: 'EA',
        template: '<th ng-repeat="month in months">{[{ month }]}</th>',
        link: function ($scope) {
           //Your code which evaluates `months`
           $scope.months = months;
        }
    };
});

答案 1 :(得分:1)

我没有看到为什么这应该在指令中。这是应该在服务中的代码。然后控制器可以在范围上公开它,html仍然可以使用ng-repeat来显示它。

您的指令给出不同响应的原因是因为它的工作方式与ngRepeat不同。 ngRepeat使用内部html作为模板,并在您给出它的循环的每次迭代中执行它。因此,它为数组中的每个元素克隆了一点DOM,然后插值。您的指令只是构建一个数组并直接输出该数组,因此您可以在DOM中获得它的json版本。

如果您真的想在指令中执行此操作,我会保持简单并使用指令的模板选项。这将允许您使用ngRepeat迭代您在指令的link函数中计算的值。

答案 2 :(得分:1)

这是jsfiddle,http://jsfiddle.net/qF3KL/

这对我有用

html

<ng-get-last-12-months></ng-get-last-12-months>

JS

.directive('ngGetLast12Months', function() {
    return {
        restrict: 'EA',
        template: '<th ng-repeat="month in months">{{month}}</th>',
        controller: function($scope) {
            var date = new Date();
            var months = [],
                monthNames = [
                    'Jan',
                    'Feb',
                    'Mar',
                    'Apr',
                    'May',
                    'Jun',
                    'Jul',
                    'Aug',
                    'Sep',
                    'Oct',
                    'Nov',
                    'Dec'
                ];
            for (var i = 0; i < 12; i++) {
                months.push(monthNames[date.getMonth()] + ' ' + date.getFullYear());
                // Subtract a month each time
                date.setMonth(date.getMonth() - 1);
            }
            $scope.months = months;
        }
    };
});