web-dev-qa-db-fra.com

Composant de sélecteur DateTime en matériau angulaire?

J'ai importé un sélecteur de date dans un projet et je me demandais s'il existait un composant officiel récent de angular) et du matériel permettant également d'inclure le temps dans le calendrier.
J'ai souvent vu des sélecteurs de temps dans la documentation matérielle et effectué des recherches dans de nombreuses sources tierces, mais elles semblent très complexes.

17
Kevin Curnow

Malheureusement, la réponse à votre question, à savoir s'il existe un support Material officiel pour la sélection de l'heure, est "Non", mais il s'agit actuellement d'un problème en suspens dans le référentiel Material2 GitHub: https://github.com/angular/ material2/issues/5648

J'espère que cela changera bientôt, en attendant, vous devrez vous battre avec ceux de tiers que vous avez déjà découverts. Dans ce numéro de GitHub, quelques personnes fournissent des solutions que vous pouvez utiliser.

14
JeremyW

Vous pouvez avoir un sélecteur de date/heure lorsque vous utilisez matInput avec le type datetime-local ainsi:

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

Vous pouvez cliquer sur chaque partie de l'espace réservé pour définir le jour, le mois, l'année, les heures, les minutes et indiquer si son heure est AM ou PM.

8
Maurice

Tant qu'il n'y a pas de date officielle et de sélecteur de temps à partir de angular lui-même, je conseillerais de faire une combinaison de valeur par défaut angular angulaire) et ceci Timepicker de matériau angulaire . J'ai choisi celui-ci car tous les autres que j'ai trouvés à ce le temps manque de support pour les problèmes, sont obsolètes ou ne fonctionnent pas bien dans les versions les plus récentes angular. Ce mec semble être très réactif.

Je les ai tous deux emballés dans un seul composant, de sorte qu'il semble que ce soit une unité. Vous devez juste vous assurer de faire quelques choses:

Quand aucune entrée n'a encore été donnée, je conseillerais:

  • En cliquant sur le composant, le sélecteur de date doit toujours être déclenché en premier.
  • Après la fermeture du sélecteur de date, le timepicker apparaît automatiquement.
  • Utilisation touchUi = true sur le sélecteur de date, de manière à ce que le sélecteur de date et le sélecteur de temps apparaissent sous forme de dialogue l'un après l'autre.
  • Assurez-vous que le sélecteur de date apparaît également lorsque vous cliquez sur le formulaire (au lieu de l'icône uniquement qui est celle par défaut).
  • Utilisez cette solution pour utiliser le timepicker également sous une forme matérielle. Lorsque vous les placez l'un derrière l'autre, il semble que ce soit une forme.

Lorsqu'une valeur a été donnée, il est clair qu'une partie contient l'heure et l'autre partie contient la date. A ce moment, il est clair que l'utilisateur doit cliquer sur l'heure pour changer l'heure et sur la date pour changer la date. Mais avant cela, donc lorsque les deux champs sont vides (et "attachés" l'un à l'autre sous la forme d'un seul champ), vous devez vous assurer que l'utilisateur ne peut pas être confondu en faisant les recommandations ci-dessus.

Mon composant n'est pas encore complet, je vais essayer de me rappeler de partager le code ultérieurement. Tirez un commentaire si cette question a plus d'un mois ou plus.

Edition: Résultat

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);
  }
}

Une source importante: https://github.com/Agranom/ngx-material-timepicker/issues/126

Je pense que cela mérite encore quelques ajustements, car je pense que cela peut fonctionner un peu mieux si je dispose de plus de temps pour créer ceci. Plus important encore, j'ai essayé de résoudre le problème UTC. Toutes les dates doivent donc être affichées en heure locale, mais doivent être envoyées au serveur au format UTC (ou au moins enregistrées avec le fuseau horaire correct ajouté).

2
CularBytes

Je vous suggère de passer à la caisse https://vlio20.github.io/angular-datepicker/

enter image description here

1
vlio20