TimeSelector / TimePicker Directive – AngularJS

Hey everyone,

I’ve been mucking around with directives for that last few days and one of my requirements has been a simple timepicker. Nothing too fancy, but if anyone would like to use it – feel free.

See the following fiddle for the demo: http://jsfiddle.net/LFB3F/2/

Timepicker Directive

Timepicker Directive

The directive is initialised with both the hour and minute defaults being set like this:


Note that hours and minutes should be set in the controller that wraps around the Timepicker:

app.controller("MyCtrl", function MyCtrl($scope) {
    $scope.hours = 11;
    $scope.minutes = 45;       
});

The hours and minutes will then be updated whenever the user changes the value. If you need any other hooks it’s fairly easy to modify and there are a heap of comments.

You may also want to put the HTML in an external template. Just make the following changes to the directive (note templateURL):

app.directive("ngTimeSelector", function () {
    return {
        restrict: 'EA',
        templateUrl: '/Directives/TimeSelector',
        scope: {
            hours: "=",
            minutes: "="
        },
        replace: true,
        link: function (scope, elem, attr) {
...
...

The JSFiddle is probably the easiest way to see how it all works. You can simply copy it from there to your app. Alternatively, I’ve dumped the code below:

Uncondensed HTML (for those who prefer to use a template)

{{displayHours()}}
{{displayMinutes()}}
PM
AM

Timepicker Directive

/* 
    http://www.whatibroke.com/?p=899
*/

var app = angular.module('myApp', []);

app.controller("MyCtrl", function MyCtrl($scope) {
    $scope.hours = 11;
    $scope.minutes = 45;       
});


app.directive("ngTimeSelector", function () {
    return {
        restrict: 'EA',
        template: '
{{displayHours()}}
{{displayMinutes()}}
PM
AM
', scope: { hours: "=", minutes: "=" }, replace: true, link: function (scope, elem, attr) { //Create vars scope.period = "AM"; /* Increases hours by one */ scope.increaseHours = function () { //Check whether hours have reached max if (scope.hours < 23) { scope.hours = ++scope.hours; } else { scope.hours = 0; } } /* Decreases hours by one */ scope.decreaseHours = function () { //Check whether hours have reached min scope.hours = scope.hours <= 0 ? 23 : --scope.hours; } /* Increases minutes by one */ scope.increaseMinutes = function () { //Check whether to reset if (scope.minutes >= 59) { scope.minutes = 0; } else { scope.minutes++; } } /* Decreases minutes by one */ scope.decreaseMinutes = function () { //Check whether to reset if (scope.minutes <= 0) { scope.minutes = 59; } else { scope.minutes = --scope.minutes; } } /* Displays hours - what the user sees */ scope.displayHours = function () { //Create vars var hoursToDisplay = scope.hours; //Check whether to reset etc if (scope.hours > 12) { hoursToDisplay = scope.hours - 12; } //Check for 12 AM etc if (hoursToDisplay == 0) { //Set to am and display 12 hoursToDisplay = 12; } else { //Check whether to prepend 0 if (hoursToDisplay <= 9) { hoursToDisplay = "0" + hoursToDisplay; } } return hoursToDisplay; } /* Displays minutes */ scope.displayMinutes = function () { return scope.minutes <= 9 ? "0" + scope.minutes : scope.minutes; } /* Switches the current period by ammending hours */ scope.switchPeriod = function () { scope.hours = scope.hours >= 12 ? scope.hours - 12 : scope.hours + 12; } } } });

Styles

body{
	background-color: #F0F0F0;
	font-family: "Lato", sans-serif;
	font-weight: 300;
	color: #363636;
}

.timeSelectorDirective {
    background: none;
    -webkit-user-select: none;      
    -moz-user-select: none;
    -ms-user-select: none;
    -o-user-select: none;
    user-select: none;
}
.timeSelectorDirective .increase, .timeSelectorDirective .decrease{
    text-align: center;
    vertical-align: middle;    
    color: rgb(112, 112, 112);    
    text-shadow: 0px 1px #FFF;
    cursor: pointer;
    -webkit-transition: 500ms ease-out all;
    -moz-transition: 500ms ease-out all;
    -ms-transition: 500ms ease-out all;
    -o-transition: 500ms ease-out all;
    transition: 500ms ease-out all;
    font-size: 100%;
    border: 1px solid #CCC;
    padding: 3px;
    margin: 3px;
    border: 1px solid #EDE;
}

.timeSelectorDirective .increase:hover, .timeSelectorDirective .decrease:hover{
    color: rgba(112, 112, 112, 0.5);   
    border-color: #CCC;
    background-color: #FFF;
}

.timeSelectorDirective .increase:active, .timeSelectorDirective .decrease:active{
    color: rgb(112, 112, 112);
    box-shadow: inset 1px 1px 1px #DDD;
}

.timeSelectorDirective .section{
    display: inline-block;
}

.timeSelectorDirective .display{
    background-color: rgb(247, 247, 247);
    color: #555555;
    padding: 5px;
    margin: 0px 3px;
    min-width: 30px;
    text-align: center;
    border: 1px solid #DDD;
    box-shadow: 1px 1px 1px #FFFFFF;
}

Sample Usage

www.whatibroke.com

Hours: {{hours}}   Minutes: {{minutes}}

Misc Includes
AngularJS: http://ajax.googleapis.com/ajax/libs/angularjs/1.1.5/angular.js
FontAwesome: http://netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.css
Font: http://fonts.googleapis.com/css?family=Lato:300,300italic,400,700,700italic|Rokkitt:400,700.css

Leave a Reply