【发布时间】:2018-07-16 22:15:42
【问题描述】:
我在一个项目中导入了一个date picker,想知道是否有任何官方最近的组件来自角度和材料,以包括日历中的时间。
我在材料文档中看到了很多时间选择器,并研究了很多第三方,但它们看起来非常复杂。
【问题讨论】:
标签: angular datepicker angular-material2 datetimepicker timepicker
我在一个项目中导入了一个date picker,想知道是否有任何官方最近的组件来自角度和材料,以包括日历中的时间。
我在材料文档中看到了很多时间选择器,并研究了很多第三方,但它们看起来非常复杂。
【问题讨论】:
标签: angular datepicker angular-material2 datetimepicker timepicker
当使用 matInput 类型为 datetime-local 时,您可以有一个日期时间选择器,如下所示:
<mat-form-field>
<input matInput type="datetime-local" placeholder="start date">
</mat-form-field>
您可以单击占位符的每个部分来设置日、月、年、小时、分钟以及是上午还是下午。
【讨论】:
dd/mm/yyyy --:-- 24 小时格式?
type="datetime-local"。它只是将其视为常规输入。 caniuse stats
我建议您结帐@angular-material-components/datetime-picker。 这是一个类似于@angular/material Datepicker 的 DatetimePicker,增加了对选择时间的支持。
【讨论】:
只要 Angular 本身没有官方日期和时间选择器,我建议将 default angular date picker 和 Angular Material Timepicker 组合起来。我之所以选择那个,是因为我此时发现的所有其他问题都缺乏对问题的支持,已经过时或在最新的 Angular 版本中运行不佳。这家伙似乎反应灵敏。
我将它们都包装在一个组件中,这样看起来就像是一个单元。你只需要确保做几件事:
如果还没有任何意见,我会建议:
touchUi = true,这样 datepicker 和 timepicker 就会作为一个对话框出现。给定一个值后,很明显一部分包含时间,另一部分包含日期。在那一刻,很明显用户必须点击时间来改变时间,点击日期来改变日期。但在此之前,因此当两个字段为空时(并且作为一个字段相互“附加”),您应该确保用户不会因执行上述建议而感到困惑。
我的组件还没有完成,我会尽量记住自己稍后分享代码。如果这个问题超过一个月左右,请发表评论。
编辑:结果
<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);
}
}
一个重要来源:https://github.com/Agranom/ngx-material-timepicker/issues/126
我认为它仍然值得一些调整,因为我认为当我有更多时间创建它时它可以更好地工作。最重要的是,我也尝试解决 UTC 问题,因此所有日期都应以当地时间显示,但应以 UTC 格式发送到服务器(或至少保存时添加了正确的时区)。
【讨论】:
很遗憾,您关于选择时间是否有官方 Material 支持的问题的答案是“否”,但目前在 Material2 官方 GitHub repo 上是一个未解决的问题:https://github.com/angular/material2/issues/5648
希望这种情况很快就会改变,与此同时,你将不得不与你已经发现的第 3 方战斗。该 GitHub 问题中有几个人提供了他们自制的解决方法,您可以尝试。
【讨论】:
自 4 年前以来,目前有一个针对 Angular 团队的官方公开问题,要求支持时间和日期时间选择器:https://github.com/angular/components/issues/5648
正如您在这篇文章中看到的那样,那里有很多库,问题是它们中的大多数已被弃用(较旧的 Angular 版本)。
所以,我实际上使用的是来自@matheo 的这个,它是我发现的最新和维护的:
https://www.npmjs.com/package/@coachcare 最近移至https://www.npmjs.com/package/@matheo/datepicker
演示:http://matheo.co/demos/datepicker
注意:如果它不适用于 Angular 版本 >= 12,请检查是否使用了新的 Angular 约定主题,例如:
@use "~@matheo/datepicker/theming" as datepicker; // ... @include datepicker.mat-datepicker-theme($main_theme);
【讨论】:
@matheo/datepicker 包包含 .mjs 文件,Node.js 以我的应用程序配置不支持的方式将其视为 ECMAScript 模块。我试着搞乱 webpack 模块配置的东西,但现在已经放弃了。导入组件会导致数百个错误如: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'.
【讨论】:
day-time-picker 的问题吗? ERROR TypeError: Cannot read property 'locale' of undefined at DayTimeCalendarService.push../node_modules/ng2-date-picker/fesm5/ng2-date-picker.js.DayTimeCalendarService.getConfig (ng2-date-picker.js:999) at DayTimeCalendarComponent.push../node_modules/ng2-date-picker/fesm5/ng2-date-picker.js.DayTimeCalendarComponent.init (ng2-date-picker.js:1691) at DayTimeCalendarComponent.push../node_modules/ng2-date-picker/fesm5/ng2-date-picker.js.DayTimeCalendarComponent.ngOnInit (ng2-date-picker.js:1687)
moment-with-locales.min.js 文件添加到我的资产文件夹中
实现日期和时间控制的最佳方式是使用输入类型“datetime-local”。 请参考https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/datetime-local
示例代码是
<mat-grid-list [cols]="5" gutterSize="20px" rowHeight="70px">
<form *ngIf="dateForm && dateForm !== null" [formGroup]="dateForm">
<mat-grid-tile>
<mat-form-field appearance="outline" floatLabel="auto">
<mat-label>From Date</mat-label>
<input type="datetime-local" matInput name="fromTime" formControlName="fromDate">
</mat-form-field>
</mat-grid-tile>
<mat-grid-tile>
<mat-form-field appearance="outline" floatLabel="auto">
<mat-label>To Date</mat-label>
<input type="datetime-local" matInput name="toTime" formControlName="toDate">
</mat-form-field>
</mat-grid-tile>
</form>
</mat-grid-list>
【讨论】: