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()}}
= 12" class="display"> PM
<div ng-if="hours 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()}}
= 12" class="display"> PM
<div ng-if="hours 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 = 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

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

jQuery DateTimePicker with Bootstrap

Hey everyone,

I ran into a bit of trouble today trying to get datetimepicker to work within bootstrap tabs. The dialog appeared however none of the buttons seemed to work. The fields also remained unpopulated.

It turned out the the issue was caused by the fact that I’d used jquery’s clone function to duplicate the tabs without reassigning field ids. This meant that there were multiple fields with the same id, confusing datetimepicker.

The solution I used was to dynamically assign all of the ids as each tab was displayed:


/* Bind tab change events: this has been done so that there is less js overhead */
function bind_tab_change_events(){

	//Bind change event
	$('.nav-tabs').bind('show', function(e){

		//Create vars
		var selected_file_id = $(e.target).data('file_id');

		//Initialisations
		initialise_time_pickers('#file_' + selected_file_id + ' .timepicker', selected_file_id);	
	})
}

/* Initalise timepickers */
function initialise_time_pickers(selector, unique_id){

	//Loop through each bound element
	$.each($(selector), function(index, value){

		//Set id - datepicker won't work without unique ids
		$(value).attr('id', $(value).attr('id') + '_' + unique_id);

		//Initialise datepicker		
		$(value).datetimepicker();
	});
}

UPDATE:
It looks like quite a few people hitting this post are looking for a bootstrap specific alternative, Sebastien has provided a link to one in the comments below:
Bootstrap DatetimePicker.

Another one that looks really good, a bit less clunky than any of the alternatives I’ve seen: http://tarruda.github.com/bootstrap-datetimepicker/

Plain timepicker: http://jdewit.github.com/bootstrap-timepicker/

Plain datepicker: http://www.eyecon.ro/bootstrap-datepicker/

Let me know if you have any questions!