The user aims to incorporate datetimepicker.js, a jQuery plugin, into an AngularJS application by developing a custom directive. The primary obstacle is that the datetimepicker does not seamlessly bind to AngularJS’s ng-model, which disrupts the two-way data binding mechanism. As a result, there are inconsistencies between the Angular model and the date chosen through the datetimepicker.

Problem Overview

  1. If the date is set via json before rendered in view, the initial date did not display, I can not see any log of the execution of ngModel render method.
  2. When I picked a date, it got a string based datetime to the json data, not a long format. And in other related fragment in the view, the string based date can not parsed by angular date filter.
  3. When used it in modal dialog, it’s value is not cleared when the modal window is popup in the next time.

Here in example we have Eonasdan/bootstrap-datetimepicker

The Eonasdan/bootstrap-datetimepicker library is a jQuery-based datetime picker and does not natively support Angular. To integrate it with Angular, you would need to use a wrapper or directive that bridges the gap between jQuery and Angular.

So here we have given solution for all angular versions

Angular JS

Directive

app.directive('datetimepicker', function() {
    return {
        restrict: 'A',
        require: 'ngModel',
        link: function(scope, element, attrs, ngModelCtrl) {
            console.log('call datetimepicker link...');
            var picker = element.datetimepicker({
                dateFormat: 'dd/MM/yyyy hh:mm:ss',
                useCurrent: false // Prevent default date setting on initialization
            });

            // Model -> View (render)
            ngModelCtrl.$render = function() {
                console.log('ngModelCtrl.$viewValue@' + ngModelCtrl.$viewValue);
                picker.setDate(ngModelCtrl.$viewValue || '');
            };

            // View -> Model (change event)
            picker.on('dp.change', function(e) {
                console.log('dp.change ' + e.date);              
                scope.$apply(function(){
                    // Store Date object in the model
                    ngModelCtrl.$setViewValue(e.date ? e.date.toISOString() : null); // Using ISO string format
                });
            });

            // Optional: Clear date when modal is opened again
            scope.$on('modalOpened', function() {
                ngModelCtrl.$setViewValue(null); // Reset the date on modal open
                picker.clear();
            });

            // Optional: Listen for modal closing event and clear date if needed
            scope.$on('modalClosed', function() {
                picker.clear();
            });
        }
    };
});

Html

Datetime Picker Example

Controller app.controller('MainCtrl', [ '$scope', function ($scope) { $scope.dueDate = new Date(); }, ]);

For Angular 2+ versions , need to install packages using below command
npm install jquery moment eonasdan-bootstrap-datetimepicker

Need to add styles and scripts in angular.json file

"styles": [
  "node_modules/bootstrap/dist/css/bootstrap.min.css",
  "node_modules/eonasdan-bootstrap-datetimepicker/build/css/bootstrap-datetimepicker.min.css"
],
"scripts": [
  "node_modules/jquery/dist/jquery.min.js",
  "node_modules/moment/min/moment.min.js",
  "node_modules/eonasdan-bootstrap-datetimepicker/build/js/bootstrap-datetimepicker.min.js"
]

Angular 18

datetime-picker.directive.ts

import $ from 'jquery';
import { Directive, ElementRef, EventEmitter, Input, OnDestroy, OnInit, Output } from '@angular/core';
import 'eonasdan-bootstrap-datetimepicker';

@Directive({
  selector: '[appDatetimepicker]',
  standalone: true
})
export class DatetimepickerDirective implements OnInit, OnDestroy {
  @Input() options: any;
  @Output() dateChange = new EventEmitter();

  private picker: any;
  constructor(private el: ElementRef) {}
  ngOnInit(): void {
    // Use type assertion to avoid TypeScript error
    this.picker = ($(this.el.nativeElement)).datetimepicker(this.options);

    this.picker.on('dp.change', (e: any) => {
      this.dateChange.emit(e.date ? e.date.format('YYYY-MM-DD HH:mm') : '');
    });
  }
  ngOnDestroy(): void {
    if (this.picker) {
      (this.picker.data('DateTimePicker')).destroy();
    }
  }
}

App.component.html

app.component.ts

import { Component } from '@angular/core';
import { DatetimepickerDirective } from './datetime-picker/datetime-picker.directive';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  standalone : true,
  imports: [DatetimepickerDirective],
})
export class AppComponent {
  datetimeOptions = {
    format: 'YYYY-MM-DD HH:mm',
    sideBySide: true,
    showTodayButton: true
  };
  onDateChange(date: string): void {
    console.log('Selected date:', date);
  }
}

Angular 2 to 17(module based)

No Standalone Components: Angular 2 to 17 doesn’t support the standalone: true flag in components or directives, so the directive needs to be declared in the module.
Module-based Declaration: The directive will be declared within an Angular module (@NgModule) instead of being standalone.

datetime-picker.directive.ts

import * as $ from 'jquery';
import { Directive, ElementRef, EventEmitter, Input, OnDestroy, OnInit, Output } from '@angular/core';
import 'eonasdan-bootstrap-datetimepicker';

@Directive({
  selector: '[appDatetimepicker]'
})
export class DatetimepickerDirective implements OnInit, OnDestroy {
  @Input() options: any;
  @Output() dateChange = new EventEmitter();

  private picker: any;
  constructor(private el: ElementRef) {}
  ngOnInit(): void {
    this.picker = $(this.el.nativeElement).datetimepicker(this.options);
    this.picker.on('dp.change', (e: any) => {
      this.dateChange.emit(e.date ? e.date.format('YYYY-MM-DD HH:mm') : '');
    });
  }
  ngOnDestroy(): void {
    if (this.picker) {
      this.picker.data('DateTimePicker').destroy();
    }
  }
}

Now need to import DatetimepickerDirective in the app module’s import array. Other than this everything is the same as angular 18.

In summary, while Eonasdan/bootstrap-datetimepicker itself is not natively compatible with Angular, there are Angular-specific wrappers and alternative libraries available that can provide similar functionality.

Support On Demand!

Angular

Related Q&A