AngularJS - 设置包装指令的有效性

AngularJS - set validity of wrapped directives

我正在研究一个简单的指令 - date/time 选择器。它包装 angular material 日期选择器和两个额外的选择(小时和分钟),构建日期并通过 ngModel.

公开它

我已经实现了验证逻辑,用户可以在其中提供最小值和最大值,如果所选日期和时间超出范围,模型有效性将设置为 false。

这是指令的标记及其代码:

<div layout="column">    
    <div layout="row">
        <md-datepicker name="selectedDatePicker" ng-model="selectedDate" flex="50" flex-order="1"></md-datepicker>
        <md-input-container flex="25" flex-order="2">
            <label>Hour</label>
            <md-select ng-model="selectedHour">
                <md-option ng-repeat="hour in hours" value="{{hour}}">
                    {{hour}}
                </md-option>
            </md-select>
        </md-input-container>
        <md-input-container flex="25" flex-order="2">
            <label>Minute</label>
            <md-select ng-model="selectedMinute">
                <md-option ng-repeat="minute in minutes" value="{{minute}}">
                    {{minute}}
                </md-option>
            </md-select>
        </md-input-container>
    </div>
    <div layout="row">
        <ng-transclude></ng-transclude>
    </div>
</div>

angular.module('myApp')
    .directive('jcdatetimepicker', function ($parse) {

        var link = function (scope, iElement, iAttrs, ngModel) {

            var initValue = scope.ngModel;
            setDateTime(initValue);

            ngModel.$parsers.push(validateInput);
            ngModel.$formatters.push(validateInput);

            ngModel.$render = function () {
                setDateTime(ngModel.$viewValue);
            }

            scope.$on('jcdatetimepicker:updateModel', function (evt, args) {                
                ngModel.$setViewValue(validateInput(args));
            });

            function validateInput(inputDate){
                var valid = true;                              

                if (angular.isDefined(scope.minValue) && (inputDate < scope.minValue)) {
                    valid = false;
                    ngModel.$setValidity('min', false);
                }
                else {                
                    ngModel.$setValidity('min', true);
                }

                if (angular.isDefined(scope.maxValue) && (inputDate > scope.maxValue)) {
                    valid = false;
                    ngModel.$setValidity('max', false);
                }
                else {
                    ngModel.$setValidity('max', true);
                }
                return valid ? inputDate : undefined;
            }

            function setDateTime(date) {
                if (angular.isDate(date)) {
                    scope.selectedMinute = date.getMinutes();
                    scope.selectedHour = date.getHours();
                    scope.selectedDate = new Date(date.getFullYear(), date.getMonth(), date.getDate());
                }                
            }
        };

        return {
            restrict: 'E',
            replace: false,
            transclude: true,
            require: '^ngModel',
            scope: {
                ngModel: '=ngModel',
                minValue: '=min',
                maxValue: '=max'
            },
            controller: 'jcDateTimePickerController',
            link: link,
            templateUrl: 'templates/shared/jcDateTimePicker/jcDatetimePicker.html'            
        }
    }).controller('jcDateTimePickerController', function ($scope, $element) {

        $scope.hours = [];
        $scope.minutes = [];

        $scope.selectedMinute = 0;
        $scope.selectedHour = 12;
        $scope.selectedDate = new Date();
        $scope.isValid = false;
        //initialize hours & minutes
        function init() {
            for (var h = 0; h < 24; h++) {
                $scope.hours.push(h);
            }
            for (var m = 0; m < 60; m++) {
                $scope.minutes.push(m);
            }
        };
        init();

        $scope.$watchGroup(['selectedMinute', 'selectedHour', 'selectedDate'], function (newVals, oldVals, _scope) {
            var minutes = newVals[0];
            var hours = newVals[1];
            var date = newVals[2];

            date.setHours(hours, minutes, 0);
            $scope.$broadcast('jcdatetimepicker:updateModel', date);
        });
    });

它在验证方面工作正常 - ngModel 正确设置了传递给我的指令的模型的有效性。问题是,当所选值无效时,我还想在我的指令包装 mdDatepikcermdSelect 的指令上设置有效性 - 这样这些指令的 UI也将指示无效输入。

但是我不知道如何获取那些包装指令,例如。 G。日期选择器并修改它的有效性。在单元测试中,我尝试使用隔离范围,但 selectedDatePicker 未定义。

这可能吗?或者是否可以获取它的 ngModel 控制器,并以这种方式设置有效性?

非常感谢任何建议。

如果你有mdDatepicker和mdSelect作用域的签名,你可以使用:angular.element($("[name='selectedDatePicker']")).scope,然后调用放弃所需行为所需的功能或设置属性。

我还没有尝试过代码,但这是一种可能的方法。