Skip to content
This repository has been archived by the owner on May 29, 2019. It is now read-only.

Commit

Permalink
feat(timepicker): add ngDisabled support
Browse files Browse the repository at this point in the history
- Adds support for `ng-disabled` on timepicker element for disabling all controls programmatically

Closes #2219
Closes #4811
  • Loading branch information
wesleycho committed Nov 3, 2015
1 parent beabb4a commit 4651191
Show file tree
Hide file tree
Showing 3 changed files with 160 additions and 38 deletions.
103 changes: 103 additions & 0 deletions src/timepicker/test/timepicker.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -2015,4 +2015,107 @@ describe('timepicker directive', function() {
expect(element.html()).toBe('<div class="ng-binding">foo</div>');
});
});

describe('ngDisabled', function() {
it('prevents modifying date via controls when true', function() {
$rootScope.disabled = false;
element = $compile('<uib-timepicker ng-model="time" ng-disabled="disabled"></uib-timepicker')($rootScope);
$rootScope.$digest();

var inputs = element.find('input');
var hoursEl = inputs.eq(0), minutesEl = inputs.eq(1),
secondsEl = inputs.eq(2);
var upKeydownEvent = keydown('up');
var downKeydownEvent = keydown('down');
var leftKeydownEvent = keydown('left');
var upMouseWheelEvent = wheelThatMouse(1);
var downMouseWheelEvent = wheelThatMouse(-1);

expect(getTimeState()).toEqual(['02', '40', '25', 'PM']);
expect(getModelState()).toEqual([14, 40, 25]);

$rootScope.disabled = true;
$rootScope.$digest();

// UP
hoursEl.trigger(upKeydownEvent);
$rootScope.$digest();
expect(getTimeState()).toEqual(['02', '40', '25', 'PM']);
expect(getModelState()).toEqual([14, 40, 25]);

minutesEl.trigger(upKeydownEvent);
$rootScope.$digest();
expect(getTimeState()).toEqual(['02', '40', '25', 'PM']);
expect(getModelState()).toEqual([14, 40, 25]);

secondsEl.trigger(upKeydownEvent);
$rootScope.$digest();
expect(getTimeState()).toEqual(['02', '40', '25', 'PM']);
expect(getModelState()).toEqual([14, 40, 25]);

// DOWN
secondsEl.trigger(downKeydownEvent);
$rootScope.$digest();
expect(getTimeState()).toEqual(['02', '40', '25', 'PM']);
expect(getModelState()).toEqual([14, 40, 25]);

minutesEl.trigger(downKeydownEvent);
$rootScope.$digest();
expect(getTimeState()).toEqual(['02', '40', '25', 'PM']);
expect(getModelState()).toEqual([14, 40, 25]);

hoursEl.trigger(downKeydownEvent);
$rootScope.$digest();
expect(getTimeState()).toEqual(['02', '40', '25', 'PM']);
expect(getModelState()).toEqual([14, 40, 25]);

// Other keydown
hoursEl.trigger(leftKeydownEvent);
$rootScope.$digest();
expect(getTimeState()).toEqual(['02', '40', '25', 'PM']);
expect(getModelState()).toEqual([14, 40, 25]);

minutesEl.trigger(leftKeydownEvent);
$rootScope.$digest();
expect(getTimeState()).toEqual(['02', '40', '25', 'PM']);
expect(getModelState()).toEqual([14, 40, 25]);

secondsEl.trigger(leftKeydownEvent);
$rootScope.$digest();
expect(getTimeState()).toEqual(['02', '40', '25', 'PM']);
expect(getModelState()).toEqual([14, 40, 25]);

// WHEEL UP
secondsEl.trigger(upMouseWheelEvent);
$rootScope.$digest();
expect(getTimeState()).toEqual(['02', '40', '25', 'PM']);
expect(getModelState()).toEqual([14, 40, 25]);

minutesEl.trigger(upMouseWheelEvent);
$rootScope.$digest();
expect(getTimeState()).toEqual(['02', '40', '25', 'PM']);
expect(getModelState()).toEqual([14, 40, 25]);

hoursEl.trigger(upMouseWheelEvent);
$rootScope.$digest();
expect(getTimeState()).toEqual(['02', '40', '25', 'PM']);
expect(getModelState()).toEqual([14, 40, 25]);

// WHEEL DOWN
secondsEl.trigger(downMouseWheelEvent);
$rootScope.$digest();
expect(getTimeState()).toEqual(['02', '40', '25', 'PM']);
expect(getModelState()).toEqual([14, 40, 25]);

minutesEl.trigger(downMouseWheelEvent);
$rootScope.$digest();
expect(getTimeState()).toEqual(['02', '40', '25', 'PM']);
expect(getModelState()).toEqual([14, 40, 25]);

hoursEl.trigger(downMouseWheelEvent);
$rootScope.$digest();
expect(getTimeState()).toEqual(['02', '40', '25', 'PM']);
expect(getModelState()).toEqual([14, 40, 25]);
});
});
});
89 changes: 54 additions & 35 deletions src/timepicker/timepicker.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,47 +74,54 @@ angular.module('ui.bootstrap.timepicker', [])
max = isNaN(dt) ? undefined : dt;
});

var disabled = false;
if ($attrs.ngDisabled) {
$scope.$parent.$watch($parse($attrs.ngDisabled), function(value) {
disabled = value;
});
}

$scope.noIncrementHours = function() {
var incrementedSelected = addMinutes(selected, hourStep * 60);
return incrementedSelected > max ||
return disabled || incrementedSelected > max ||
(incrementedSelected < selected && incrementedSelected < min);
};

$scope.noDecrementHours = function() {
var decrementedSelected = addMinutes(selected, -hourStep * 60);
return decrementedSelected < min ||
return disabled || decrementedSelected < min ||
(decrementedSelected > selected && decrementedSelected > max);
};

$scope.noIncrementMinutes = function() {
var incrementedSelected = addMinutes(selected, minuteStep);
return incrementedSelected > max ||
return disabled || incrementedSelected > max ||
(incrementedSelected < selected && incrementedSelected < min);
};

$scope.noDecrementMinutes = function() {
var decrementedSelected = addMinutes(selected, -minuteStep);
return decrementedSelected < min ||
return disabled || decrementedSelected < min ||
(decrementedSelected > selected && decrementedSelected > max);
};

$scope.noIncrementSeconds = function() {
var incrementedSelected = addSeconds(selected, secondStep);
return incrementedSelected > max ||
return disabled || incrementedSelected > max ||
(incrementedSelected < selected && incrementedSelected < min);
};

$scope.noDecrementSeconds = function() {
var decrementedSelected = addSeconds(selected, -secondStep);
return decrementedSelected < min ||
return disabled || decrementedSelected < min ||
(decrementedSelected > selected && decrementedSelected > max);
};

$scope.noToggleMeridian = function() {
if (selected.getHours() < 12) {
return addMinutes(selected, 12 * 60) > max;
return disabled || addMinutes(selected, 12 * 60) > max;
} else {
return addMinutes(selected, -12 * 60) < min;
return disabled || addMinutes(selected, -12 * 60) < min;
}
};

Expand Down Expand Up @@ -200,56 +207,68 @@ angular.module('ui.bootstrap.timepicker', [])
};

hoursInputEl.bind('mousewheel wheel', function(e) {
$scope.$apply(isScrollingUp(e) ? $scope.incrementHours() : $scope.decrementHours());
if (!disabled) {
$scope.$apply(isScrollingUp(e) ? $scope.incrementHours() : $scope.decrementHours());
}
e.preventDefault();
});

minutesInputEl.bind('mousewheel wheel', function(e) {
$scope.$apply(isScrollingUp(e) ? $scope.incrementMinutes() : $scope.decrementMinutes());
if (!disabled) {
$scope.$apply(isScrollingUp(e) ? $scope.incrementMinutes() : $scope.decrementMinutes());
}
e.preventDefault();
});

secondsInputEl.bind('mousewheel wheel', function(e) {
$scope.$apply((isScrollingUp(e)) ? $scope.incrementSeconds() : $scope.decrementSeconds());
if (!disabled) {
$scope.$apply((isScrollingUp(e)) ? $scope.incrementSeconds() : $scope.decrementSeconds());
}
e.preventDefault();
});
};

// Respond on up/down arrowkeys
this.setupArrowkeyEvents = function(hoursInputEl, minutesInputEl, secondsInputEl) {
hoursInputEl.bind('keydown', function(e) {
if (e.which === 38) { // up
e.preventDefault();
$scope.incrementHours();
$scope.$apply();
} else if (e.which === 40) { // down
e.preventDefault();
$scope.decrementHours();
$scope.$apply();
if (!disabled) {
if (e.which === 38) { // up
e.preventDefault();
$scope.incrementHours();
$scope.$apply();
} else if (e.which === 40) { // down
e.preventDefault();
$scope.decrementHours();
$scope.$apply();
}
}
});

minutesInputEl.bind('keydown', function(e) {
if (e.which === 38) { // up
e.preventDefault();
$scope.incrementMinutes();
$scope.$apply();
} else if (e.which === 40) { // down
e.preventDefault();
$scope.decrementMinutes();
$scope.$apply();
if (!disabled) {
if (e.which === 38) { // up
e.preventDefault();
$scope.incrementMinutes();
$scope.$apply();
} else if (e.which === 40) { // down
e.preventDefault();
$scope.decrementMinutes();
$scope.$apply();
}
}
});

secondsInputEl.bind('keydown', function(e) {
if (e.which === 38) { // up
e.preventDefault();
$scope.incrementSeconds();
$scope.$apply();
} else if (e.which === 40) { // down
e.preventDefault();
$scope.decrementSeconds();
$scope.$apply();
if (!disabled) {
if (e.which === 38) { // up
e.preventDefault();
$scope.incrementSeconds();
$scope.$apply();
} else if (e.which === 40) { // down
e.preventDefault();
$scope.decrementSeconds();
$scope.$apply();
}
}
});
};
Expand Down
6 changes: 3 additions & 3 deletions template/timepicker/timepicker.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@
</tr>
<tr>
<td class="form-group" ng-class="{'has-error': invalidHours}">
<input style="width:50px;" type="text" placeholder="HH" ng-model="hours" ng-change="updateHours()" class="form-control text-center" ng-readonly="::readonlyInput" maxlength="2" tabindex="{{::tabindex}}">
<input style="width:50px;" type="text" placeholder="HH" ng-model="hours" ng-change="updateHours()" class="form-control text-center" ng-readonly="::readonlyInput" maxlength="2" tabindex="{{::tabindex}}" ng-disabled="disabled">
</td>
<td>:</td>
<td class="form-group" ng-class="{'has-error': invalidMinutes}">
<input style="width:50px;" type="text" placeholder="MM" ng-model="minutes" ng-change="updateMinutes()" class="form-control text-center" ng-readonly="::readonlyInput" maxlength="2" tabindex="{{::tabindex}}">
<input style="width:50px;" type="text" placeholder="MM" ng-model="minutes" ng-change="updateMinutes()" class="form-control text-center" ng-readonly="::readonlyInput" maxlength="2" tabindex="{{::tabindex}}" ng-disabled="disabled">
</td>
<td ng-show="showSeconds">:</td>
<td class="form-group" ng-class="{'has-error': invalidSeconds}" ng-show="showSeconds">
<input style="width:50px;" type="text" ng-model="seconds" ng-change="updateSeconds()" class="form-control text-center" ng-readonly="readonlyInput" maxlength="2" tabindex="{{::tabindex}}">
<input style="width:50px;" type="text" ng-model="seconds" ng-change="updateSeconds()" class="form-control text-center" ng-readonly="readonlyInput" maxlength="2" tabindex="{{::tabindex}}" ng-disabled="disabled">
</td>
<td ng-show="showMeridian"><button type="button" ng-class="{disabled: noToggleMeridian()}" class="btn btn-default text-center" ng-click="toggleMeridian()" ng-disabled="noToggleMeridian()" tabindex="{{::tabindex}}">{{meridian}}</button></td>
</tr>
Expand Down

0 comments on commit 4651191

Please sign in to comment.