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
正确设置了传递给我的指令的模型的有效性。问题是,当所选值无效时,我还想在我的指令包装 mdDatepikcer
和 mdSelect
的指令上设置有效性 - 这样这些指令的 UI也将指示无效输入。
但是我不知道如何获取那些包装指令,例如。 G。日期选择器并修改它的有效性。在单元测试中,我尝试使用隔离范围,但 selectedDatePicker
未定义。
这可能吗?或者是否可以获取它的 ngModel
控制器,并以这种方式设置有效性?
非常感谢任何建议。
如果你有mdDatepicker和mdSelect作用域的签名,你可以使用:angular.element($("[name='selectedDatePicker']")).scope,然后调用放弃所需行为所需的功能或设置属性。
我还没有尝试过代码,但这是一种可能的方法。
我正在研究一个简单的指令 - 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
正确设置了传递给我的指令的模型的有效性。问题是,当所选值无效时,我还想在我的指令包装 mdDatepikcer
和 mdSelect
的指令上设置有效性 - 这样这些指令的 UI也将指示无效输入。
但是我不知道如何获取那些包装指令,例如。 G。日期选择器并修改它的有效性。在单元测试中,我尝试使用隔离范围,但 selectedDatePicker
未定义。
这可能吗?或者是否可以获取它的 ngModel
控制器,并以这种方式设置有效性?
非常感谢任何建议。
如果你有mdDatepicker和mdSelect作用域的签名,你可以使用:angular.element($("[name='selectedDatePicker']")).scope,然后调用放弃所需行为所需的功能或设置属性。
我还没有尝试过代码,但这是一种可能的方法。