Я импортировал средство выбора даты в проект и задавался вопросом, есть ли какой-нибудь официальный недавний компонент из angular материалов и материалов, чтобы также включить время в календарь.
Я видел много сборщиков времени в документации по материалам и исследовал множество сторонних, но они кажутся очень сложными.
Компонент выбора даты и времени с угловым материалом?
Ответ 1
К сожалению, ответ на ваш вопрос о том, есть ли официальная материальная поддержка для выбора времени, - "Нет", но в настоящее время это открытая проблема на официальном репозитории GitHub на Material2: https://github.com/angular/material2/issues/5648
Надеюсь, это скоро изменится, а вам придется бороться со сторонними, которых вы уже обнаружили. В этом выпуске GitHub есть несколько человек, которые предлагают свои собственные решения, которые вы можете попробовать.
Ответ 2
При использовании matInput
с типом datetime-local
можно использовать matInput
datetime-local
например:
<mat-form-field>
<input matInput type="datetime-local" placeholder="start date">
</mat-form-field>
Вы можете нажать на каждую часть заполнителя, чтобы установить день, месяц, год, часы, минуты и будь то AM или PM.
Ответ 3
Поскольку нет официальной системы выбора даты и времени от самого Angular, я бы посоветовал сделать комбинацию из стандартной программы выбора угловой даты и этой модели Angular Material Timepicker. Я выбрал этот, потому что все остальные, которые я обнаружил в это время, не поддерживают проблемы, устарели или не работают должным образом в самых последних версиях. Этот парень кажется очень отзывчивым.
Я обернул их обоих в один компонент, так что похоже, что это один блок. Вы просто должны сделать несколько вещей:
Когда еще не было предоставлено никакой информации, я бы посоветовал:
- При щелчке по компоненту указатель даты всегда должен запускаться первым.
- После того, как средство выбора даты закроется, оно автоматически откроется.
- Используйте
touchUi = true
, чтобы и указатель даты, и указатель времени появлялись в виде диалоговых окон друг за другом. - Убедитесь, что указатель даты также отображается при нажатии на форму (а не только на значок, который используется по умолчанию).
- Используйте это решение, чтобы использовать указатель времени также в материальной форме, при размещении их друг за другом, похоже, что это одна форма.
После того, как значение было задано, становится ясно, что одна часть содержит время, а другая часть содержит дату. В этот момент становится ясно, что пользователь должен нажать на время, чтобы изменить время, и на дату, чтобы изменить дату. Но перед этим, поэтому, когда оба поля пусты (и "привязаны" друг к другу как одно поле), вы должны убедиться, что пользователь не может быть сбит с толку, выполняя приведенные выше рекомендации.
Мой компонент еще не завершен, я постараюсь вспомнить себя, чтобы поделиться кодом позже. Сделайте комментарий, если этому вопросу больше месяца или около того.
Изменение: результат
<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 (или, по крайней мере, сохраняться с добавлением правильного часового пояса).
Ответ 4
Я бы предложил вам оформить заказ https://vlio20.github.io/angular-datepicker/
Ответ 5
Похоже, что не так уж сложно сделать выбор времени самостоятельно. Это решение выглядит как самый чистый способ:
- Получить ссылку на оверлей DataPickers. Он выставляет его через
_popupRef
(это не свойствоprivate
). Тогда получите его хост-элемент. - Когда выдает DateStickers OpenStream, создайте встроенное представление с вашим собственным компонентом выбора времени, возьмите его
rootNodes
и добавьте каждый к первому дочернему элементу 'элементов хоста' DatePickers.
Практически вся логика:
ngAfterViewInit() {
let viewRef: EmbeddedViewRef<any>;
let portalHost: Node;
this.picker.openedStream.subscribe(() => {
viewRef = this.viewContainerRef.createEmbeddedView(this.pageActionsTmplRef);
portalHost = this.picker._popupRef.hostElement;
viewRef.rootNodes.forEach(n => {
portalHost.firstChild.appendChild(n)
})
})
this.picker.closedStream.subscribe(() => {
viewRef.rootNodes.forEach(n => {
portalHost.firstChild.removeChild(n)
})
})
}
Некоторые из предстоящих проблем:
- Когда дата выбрана, по умолчанию она закрывает оверлей. Чтобы решить эту проблему, вы можете:
this.defaultCloseFunc = this.picker.close;
this.picker.close = () => {};
// And when need to close:
this.picker.close = this.defaultCloseFunc;
this.picker.close()
Все просто. Тем не менее, он не будет закрываться при щелчке снаружи, поэтому нужно зарегистрировать прослушиватель событий, который проверяет, произошел ли щелчок внутри оверлея наложения
- Вероятно, понадобятся некоторые изменения CSS. Ex.
display: block
,box-shadow: none
и т.д. Также анимация происходит при отображении сборщика. Для этого вы можете удалить его, импортировав модуль NoopAnimation из Material.
Ответ 6
Похоже, что не так уж сложно сделать выбор времени самостоятельно. Это решение выглядит как самый чистый способ:
- Получить ссылку на оверлей DataPickers. Он выставляет его через
_popupRef
(это не свойствоprivate
). Тогда получите его хост-элемент. - Когда выдает DateStickers OpenStream, создайте встроенное представление с вашим собственным компонентом выбора времени, возьмите его
rootNodes
и добавьте каждый к первому дочернему элементу 'элементов хоста' DatePickers.
ngAfterViewInit() {
let viewRef: EmbeddedViewRef<any>;
let overlayHost: Node;
this.picker.openedStream.subscribe(() => {
viewRef = this.viewContainerRef.createEmbeddedView(this.timePickerRef);
overlayHost = this.picker._popupRef.hostElement;
viewRef.rootNodes.forEach(n => {
overlayHost.firstChild.firstChild.appendChild(n)
})
})
this.picker.closedStream.subscribe(() => {
viewRef.rootNodes.forEach(n => {
overlayHost.firstChild.firstChild.removeChild(n)
})
})
}
А когда выбирается дата, по умолчанию закрывается оверлей. Чтобы решить эту проблему, вы можете:
this.defaultCloseFunc = this.picker.close;
this.picker.close = () => {};
// And when need to close:
this.picker.close = this.defaultCloseFunc;
this.picker.close()
Все просто. Тем не менее, он не будет закрываться при щелчке снаружи, поэтому нужно зарегистрировать прослушиватель событий, который проверяет, произошел ли щелчок внутри оверлея наложения