创建此Angular Directive的最佳方法 - from / to date选择器指令

时间:2013-11-21 18:29:39

标签: javascript angularjs directive

我的网络应用程序中有来自/迄今为止的选择,如下所示:

<div class="date-picker-horizontal">
    <i class="icon-calendar"></i> 
    Select Date: 
    <input bs-datepicker type="text" ng-model="fromDate" /> to 
    <input bs-datepicker type="text" ng-model="toDate" /> 
    <a class="btn" ng-click="loadData()"><i class="icon-refresh"></i></a>
    <div class="loading" ng-show="isLoading"></div>
</div>

我需要在我的网络应用中的多个地方使用它,所以我创建了它作为指令,它正在工作。我从范围传递值,如下:

<div ng-controller="myController">
   <from-to-date-selector data-from-date="fromDate" data-to-date="toDate" data-on-refresh="loadData()" data-is-loading="isLoading" />
   <from-to-date-selector data-from-date="lastYearsDate" data-to-date="thisYearsData" data-on-refresh="loadYearlyData()" data-is-loading="isYearlyLoading" />
</div>

我的控制器“myController”的范围包含传递给指令的每个变量(fromDate,toDate,lastYearsDate等)以及加载数据的函数(loadData(),loadYearlyData())。

我想我想知道这是否是正确的做法?我对Angular很新,并且不想从养成坏习惯开始。是否将一大堆值传递给指令性的不良做法?

1 个答案:

答案 0 :(得分:0)

我认为将变量发送到指令没有任何问题,但是我可能不会将“loadYearlyData()”作为要执行的函数发送。这听起来应该在父范围内,并且可以在将来进行操作。复杂数据也倾向于大幅降低指令的可重用性。

我花了相当多的时间来构建我公司网站的日期范围指令。我把它放在这里,因为看到另一种方法可能会有用。

注意:这可能不是一个完美的答案。它提供了想法和见解。

一些警告:

  • 我使用时间戳,所有时间都是UTC
  • 我使用bootstrap datepicker,通过自定义修改来增加时间(但是这只适用于日期选择器)
  • 我使用moment.js进行日期解析。我不会因为懒惰而注入服务。

日期范围指令模板

<div class="date-group">
    <input type="text" name="dateRangeStartsAt" ng-model="dateRangeStartsAt" date-start-date="dateRangeMinDate" date-end-date="dateRangeMaxDate" date-time required>
    <span class="text-small text-minor">- to -</span>
    <input type="text" name="dateRangeEndsAt" ng-model="dateRangeEndsAt" date-start-date="dateRangeMinDate" date-end-date="dateRangeMaxDate" date-time required>
</div>

日期范围:

ngApp.directive("uiDateRange", function($timeout) {
    return {
        templateUrl: '/assets/partials/date-range-directive.html',
        scope: {
            'dateRangeStartsAt': '=',
            'dateRangeEndsAt': '=',
            'dateRangeMinDate': '=',
            'dateRangeMaxDate': '=',
            'dateRangeForm': '=',
            'onDateChange': '&',
            'hideTime': '='
        },
        link: function(scope, element, attrs) {
            scope.$watch('dateRangeStartsAt+dateRangeEndsAt', function(newValue, oldValue) {
                // console.log("Change in date", scope.dateRangeStartsAt, scope.dateRangeEndsAt);                   

                if (scope.dateRangeStartsAt && scope.dateRangeEndsAt) {
                    var startsAt = _.isNumber(scope.dateRangeStartsAt) ? scope.dateRangeStartsAt : moment.utc(scope.dateRangeStartsAt + " UTC").valueOf();
                    var endsAt = _.isNumber(scope.dateRangeEndsAt) ? scope.dateRangeEndsAt : moment.utc(scope.dateRangeEndsAt + " UTC").valueOf();

                    var isValid = startsAt < endsAt;
                    if (scope.dateRangeMinDate && isValid) isValid = startsAt >= scope.dateRangeMinDate;
                    if (scope.dateRangeMaxDate && isValid) isValid = endsAt <= scope.dateRangeMaxDate;

                    if(scope.onDateChange) scope.onDateChange();

                    setValidity(isValid);
                } else {
                    setValidity(true);
                }
            });

            function setValidity(isValid) {
                element.find(".date-group").toggleClass("ng-invalid", !isValid);
                if (scope.dateRangeForm && scope.dateRangeForm.dateRangeStartsAt) scope.dateRangeForm.dateRangeStartsAt.$setValidity("dateRange", isValid);
            }    
        }
    }
});

日期时间:

ngApp.directive('dateTime', function($timeout) {
    return {
        restrict: 'A',
        require: '?ngModel',
        link: function(scope, element, attrs, ngModel) {
            if (!ngModel) {
                console.warn('no model, returning');
                return;
            }

            var startDate = scope.$eval(attrs.dateStartDate);
            var endDate = scope.$eval(attrs.dateEndDate);
            var api;

            // element.datetimepicker({
            $timeout(function () {
                element.datetimepicker({
                    format: "mm/dd/yyyy hh:ii"
                    , autoclose: true
                    // , startDate: (startDate) ? new Date(startDate) : null
                    // , endDate: (endDate) ? new Date(endDate) : null
                    , pickerPosition: 'bottom-left'
                });    
            });


            // Angular doesn't update val, do it manually
            if(scope.$eval(attrs.ngModel)) {
                render();
            }

            scope.$watch(attrs.ngModel, function (newValue) {
                render();
            });


            element.bind('blur keyup change changeDate', function() {
                scope.$apply(read);
            });

            read();    

            function read() {
                ngModel.$setViewValue(element.val());
            }

            function render() {
                var date = scope.$eval(attrs.ngModel);

                // Convert timestamp to string date                 
                if(_.isNumber(date)) date = moment.utc(scope.$eval(attrs.ngModel)).format("MM/DD/YYYY HH:mm");

                element.val(date);
            }
        }
    }
});