Angular-Material DateTime Picker Component?

149,134

Solution 1

You can have a datetime picker when using matInput with type datetime-local like so:

  <mat-form-field>
    <input matInput type="datetime-local" placeholder="start date">
  </mat-form-field>

You can click on each part of the placeholder to set the day, month, year, hours,minutes and whether its AM or PM.

Solution 2

I recommend you to checkout @angular-material-components/datetime-picker. This is a DatetimePicker like @angular/material Datepicker by adding support for choosing time.

enter image description here

Solution 3

For as long as there is no official date and time picker from angular itself, I would advise to make a combination of the default angular date picker and this Angular Material Timepicker. I've chosen that one because all the other ones I found at this time lack support for issues, are outdated or are not functioning well in the most recent angular versions. This guy seems to be very responsive.

I've wrapped them both in one component so that it looks like it is one unit. You just have to make sure to do a few things:

When no input has been given yet, I would advise:

  • On-click of the component, the datepicker should always be triggered first.
  • After the datepicker closes, have the timepicker automatically popup.
  • Use touchUi = true on the datepicker, so that both the datepicker and the timepicker come as a dialog after each other.
  • Make sure the datepicker also shows up when clicking on the form (instead of only on the icon which is the default).
  • Use this solution to use the timepicker also in a material form, when placing them behind each other, it looks like it is one form.

After a value has been given, it is clear that one part contains the time and the other part contains the date. At that moment it is clear that the user has to click on the time to change the time, and on the date to change the date. But before that, so when both fields are empty (and 'attached' to each other as one field) you should make sure the user cannot be confused by doing above recommendations.

My component is not complete yet, I will try to remember myself to share the code later. Shoot a comment if this question is more then a month old or so.

Edit: Result

enter image description here

<div fxLayout="row">
  <div *ngIf="!dateOnly" [formGroup]="timeFormGroup">
    <mat-form-field>
      <input matInput [ngxTimepicker]="endTime" [format]="24"  placeholder="{{placeholderTime}}" formControlName="endTime" />
    </mat-form-field>
    <ngx-material-timepicker #endTime (timeSet)="timeChange($event)" [minutesGap]="10"></ngx-material-timepicker>
  </div>
  <div>
    <mat-form-field>
      <input id="pickerId" matInput [matDatepicker]="datepicker" placeholder="{{placeholderDate}}" [formControl]="dateForm"
             [min]="config.minDate" [max]="config.maxDate" (dateChange)="dateChange($event)">
      <mat-datepicker-toggle matSuffix [for]="datepicker"></mat-datepicker-toggle>
      <mat-datepicker #datepicker [disabled]="disabled" [touchUi]="config.touchUi" startView="{{config.startView}}"></mat-datepicker>
    </mat-form-field>
  </div>
</div>
import { Component, OnInit, Input, EventEmitter, Output } from '@angular/core';
import { FormControl, FormGroup } from '@angular/forms';
import { DateAdapter, MatDatepickerInputEvent } from '@angular/material';

import * as moment_ from 'moment';

const moment = moment_;

import { MAT_MOMENT_DATE_ADAPTER_OPTIONS } from '@angular/material-moment-adapter';

class DateConfig {
  startView: 'month' | 'year' | 'multi-year';
  touchUi: boolean;
  minDate: moment_.Moment;
  maxDate: moment_.Moment;
}

@Component({
  selector: 'cb-datetimepicker',
  templateUrl: './cb-datetimepicker.component.html',
  styleUrls: ['./cb-datetimepicker.component.scss'],
})
export class DatetimepickerComponent implements OnInit {

  @Input() disabled: boolean;
  @Input() placeholderDate: string;
  @Input() placeholderTime: string;
  @Input() model: Date;
  @Input() purpose: string;
  @Input() dateOnly: boolean;

  @Output() dateUpdate = new EventEmitter<Date>();

  public pickerId: string = "_" + Math.random().toString(36).substr(2, 9);

  public dateForm: FormControl;
  public timeFormGroup: FormGroup;
  public endTime: FormControl;

  public momentDate: moment_.Moment;
  public config: DateConfig;

  //myGroup: FormGroup;


  constructor(private adapter : DateAdapter<any>) { }

  ngOnInit() {

    this.adapter.setLocale("nl-NL");//todo: configurable
    this.config = new DateConfig();
    if (this.purpose === "birthday") {
      this.config.startView = 'multi-year';
      this.config.maxDate = moment().add('year', -15);
      this.config.minDate = moment().add('year', -90);
      this.dateOnly = true;
    } //add more configurations
    else {
      this.config.startView = 'month';
      this.config.maxDate = moment().add('year', 100);
      this.config.minDate = moment().add('year', -100);
    }


    if (window.screen.width < 767) {
      this.config.touchUi = true;
    }



    if (this.model) {
      var mom = moment(this.model);
      if (mom.isBefore(moment('1900-01-01'))) {
        this.momentDate = moment();
      } else {
        this.momentDate = mom;
      }
    } else {
      this.momentDate = moment();
    }

    this.dateForm = new FormControl(this.momentDate);
    if (this.disabled) {
      this.dateForm.disable();
    }
    this.endTime = new FormControl(this.momentDate.format("HH:mm"));

    this.timeFormGroup = new FormGroup({
      endTime: this.endTime
    });


  }


  public dateChange(date: MatDatepickerInputEvent<any>) {

    if (moment.isMoment(date.value)) {
      this.momentDate = moment(date.value);
      if (this.dateOnly) {
        this.momentDate = this.momentDate.utc(true);
      } 
      var newDate = this.momentDate.toDate();
      this.model = newDate;
      this.dateUpdate.emit(newDate);
    }

    console.log("datechange",date);
  }

  public timeChange(time: string) {

    var splitted = time.split(':');
    var hour = splitted[0];
    var minute = splitted[1];

    console.log("time change", time);
   this.momentDate = this.momentDate.set('hour', parseInt(hour));
    this.momentDate = this.momentDate.set('minute', parseInt(minute));

    var newDate = this.momentDate.toDate();
    this.model = newDate;
    this.dateUpdate.emit(newDate);
  }
}

One important source: https://github.com/Agranom/ngx-material-timepicker/issues/126

I think it still deserves some tweaks, as I think it can work a bit better when I would have more time creating this. Most importantly I tried to solve the UTC issue as well, so all dates should be shown in local time but should be sent to the server in UTC format (or at least saved with the correct timezone added to it).

Solution 4

Unfortunately, the answer to your question of whether there is official Material support for selecting the time is "No", but it's currently an open issue on the official Material2 GitHub repo: https://github.com/angular/material2/issues/5648

Hopefully this changes soon, in the mean time, you'll have to fight with the 3rd-party ones you've already discovered. There are a few people in that GitHub issue that provide their self-made workarounds that you can try.

Solution 5

Currently there's an official Open Issue against Angular Team since 4 years ago requesting to support Time and DateTime picker: https://github.com/angular/components/issues/5648

There are plenty of libraries out there as you can see on this post, problem is most of them are deprecated (older Angular versions).

So, I'm actually using this one from @matheo, it's the most recent and maintained I've found:

https://www.npmjs.com/package/@coachcare which was moved recently to https://www.npmjs.com/package/@matheo/datepicker


Demo: http://matheo.co/demos/datepicker



NOTE: If it doesn't work for Angular version >= 12 please check that new Angular convention theming is being used, e.g.:

@use "~@matheo/datepicker/theming" as datepicker;
// ...
@include datepicker.mat-datepicker-theme($main_theme);
Share:
149,134
Kevin Curnow
Author by

Kevin Curnow

Recent graduate of 12 week intensive .NET bootcamp at Eleven Fifty Academy in Fishers, Indiana.

Updated on July 08, 2021

Comments

  • Kevin Curnow
    Kevin Curnow almost 3 years

    I imported a date picker in a project and was wondering if there was any official recent component from angular and material to include time in the calendar as well.
    I've seen plenty of time pickers in material documentation and researched a lot of third party ones, but they seem very complex.

  • TheMonkWhoSoldHisCode
    TheMonkWhoSoldHisCode over 5 years
    @KevinCurnow : Can you share the solution. I require a date range picker along with time picker. Another constraint I have is that I need to make it work in Angular4. I am aware there is one available for 6
  • Tim Harker
    Tim Harker almost 5 years
    A month old or so... curious of your solution :-).
  • CularBytes
    CularBytes almost 5 years
    @TimHarker Not 100% happy with the outcome, needs some tweaks but I tihnk it is a good start, I didn't solve the requirements that I mentioned, it is still on the todo list. So feel free to complete my requirements and update the answer :)
  • Kirataka
    Kirataka almost 5 years
    Any idea how to resolve this issue for this day-time-picker? ERROR TypeError: Cannot read property 'locale' of undefined at DayTimeCalendarService.push../node_modules/ng2-date-picker/f‌​esm5/ng2-date-picker‌​.js.DayTimeCalendarS‌​ervice.getConfig (ng2-date-picker.js:999) at DayTimeCalendarComponent.push../node_modules/ng2-date-picker‌​/fesm5/ng2-date-pick‌​er.js.DayTimeCalenda‌​rComponent.init (ng2-date-picker.js:1691) at DayTimeCalendarComponent.push../node_modules/ng2-date-picker‌​/fesm5/ng2-date-pick‌​er.js.DayTimeCalenda‌​rComponent.ngOnInit (ng2-date-picker.js:1687)
  • Kirataka
    Kirataka almost 5 years
    I installed dependencies as well (moment & tslib)
  • vlio20
    vlio20 almost 5 years
    You need moment locale I guess
  • Kirataka
    Kirataka almost 5 years
    I did added moment-with-locales.min.js file into my assets folder
  • vlio20
    vlio20 almost 5 years
    I suggest you open an issue in the github repo, stackblitz will help
  • mohax
    mohax over 4 years
    Is there a way to set locale for input? I.e. to have dd/mm/yyyy --:-- in 24 hours format?
  • Maurice
    Maurice over 4 years
    @mohax check the examples page on material.angular.com material.angular.io/components/datepicker/examples One of the examples is switching locale with a DateAdapter object. Maybe that is what your looking for. I don't have any experience with it myself
  • mhodges
    mhodges over 4 years
    This works beautifully on Chrome and MS Edge as of Oct 2019. Firefox has no support for type="datetime-local" as of right now. It just treats it as a regular input. caniuse stats
  • lostintranslation
    lostintranslation over 3 years
    Be careful, type="datetime-local" is a browser implementation, this is not an angular material styled component.
  • HughHughTeotl
    HughHughTeotl about 3 years
    This library has very poor documentation around support for locales, and there are significant errors in the sample code. It's practically impossible to use unless you happen to want exactly the default settings (and US-only locale). There are open requests from months and months ago to fix, but no visible activity on them. I would avoid.
  • Pedro Bezanilla
    Pedro Bezanilla almost 3 years
    Agranom lib is outdated (supports max. Angular 8)
  • CularBytes
    CularBytes almost 3 years
    Thanks for the headsup Pedro, seems like he is now a bit less active then 2 years ago, always difficult with open-source libs to have someone stay committed to the project.
  • icguy
    icguy over 2 years
    @mhodges as of pretty much this week (2021 October 5.) Firefox supports type="datetime-local"
  • sem10
    sem10 over 2 years
    Does this one support setting timezone for the datepicker? @Pedro
  • Pedro Bezanilla
    Pedro Bezanilla over 2 years
    Hi @AleksandarT, theorically yes BUT I'm having lot of troubles implementing that ......
  • fartwhif
    fartwhif over 2 years
    firefox version 96 (latest as of 1/28/2022) it sort of works, half the AM/PM element is hidden by the X button, and the popup widget doesn't show the time elements, only the calendar... so yeah NOPE
  • fartwhif
    fartwhif over 2 years
    For angular 8 (and other, older versions, I suspect) you would have to fork the entire project and engineer a correction to it to make it work... github.com/h2qutc/angular-material-components/issues/53
  • fartwhif
    fartwhif over 2 years
    The @matheo/datepicker package includes .mjs files, treated by Node.js as ECMAScript modules in a way that isn't supported by the configuration of my application. I tried messing around with webpack module configuration stuff but have given up for now. Importing the component results in hundreds of errors such as: Microsoft.AspNetCore.SpaServices: Error: ERROR in ../node_modules/@matheo/datepicker/core/datetime/index.d.ts:‌​8:21 - error TS2694: Namespace '"C:/projects/app/node_modules/@angular/core/core"' has no exported member '╔╡╔╡FactoryDeclaration'.
  • fartwhif
    fartwhif over 2 years
    this works, but firefox and chrome give it different features, in chrome you get a little analog clock icon, when clicked produces a dropdown helper, but these are absent in firefox.