TimeSelector / TimePicker Directive - AngularJS

AngularJSGuidesWeb Development

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/

Image unavailable in the original archive: 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)

<div class="timeSelectorDirective"> 
    <div class="section hours">
        <div class="increase">
            <i class="icon fa fa-caret-up"></i>
        </div>
        <div class="display">
            {{displayHours()}}
        </div>        
         <div class="decrease">
            <i class="icon fa fa-caret-down"></i>
        </div>
    </div>
    <div class="section minutes">
        <div class="increase">
            <i class="icon fa fa-caret-up"></i>
        </div>
        <div class="display">
            {{displayMinutes()}}
        </div>        
         <div class="decrease">
            <i class="icon fa fa-caret-down"></i>
        </div>
    </div>    
    <div class="section hours">
        <div class="increase">
            <i class="icon fa fa-caret-up"></i>
        </div>
        <div>= 12" class="display">
            PM
        </div>
        <div ng-if="hours 
            AM
        </div>   
         <div class="decrease">
            <i class="icon fa fa-caret-down"></i>
        </div>
    </div>
</div>

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: '<div class="timeSelectorDirective"> <div class="section hours"> <div class="increase"> <i class="icon fa fa-caret-up"></i> </div> <div class="display"> {{displayHours()}} </div> <div class="decrease"> <i class="icon fa fa-caret-down"></i> </div> </div> <div class="section minutes"> <div class="increase"> <i class="icon fa fa-caret-up"></i> </div> <div class="display"> {{displayMinutes()}} </div> <div class="decrease"> <i class="icon fa fa-caret-down"></i> </div> </div> <div class="section hours"> <div class="increase"> <i class="icon fa fa-caret-up"></i> </div> <div>= 12" class="display"> PM </div> <div ng-if="hours  AM </div> <div class="decrease"> <i class="icon fa fa-caret-down"></i> </div> </div> </div>',
        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 = 59) {
                    scope.minutes = 0;
                }
                else {
                    scope.minutes++;
                }
            }

            /* Decreases minutes by one */
            scope.decreaseMinutes = function () {

                //Check whether to reset
                if (scope.minutes  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 = 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

<div>
    <h1><a href='http://www.whatibroke.com/?p=899'>www.whatibroke.com</a></h1>
    
    <div style="margin-top:40px;">
        <b>Hours: </b>{{hours}}  
        <b>Minutes: </b>{{minutes}}
        
    </div>
</div>

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