From 9eacd4c333bef7b2cf6d74073083cf907a7c679b Mon Sep 17 00:00:00 2001 From: Timon Borter Date: Mon, 13 Mar 2023 21:33:23 +0100 Subject: [PATCH 1/2] feat(#163): support for action buttons as requested in issue #163. the datetime-picker does still close itself if you reach "the end of the selection". e.g. when selecting the minutes in the minutes-view. this is in contrary to the original material date picker, but in my personal opinion more useful. I think it should be possible to customize this behaviour too (via property). --- .../core/src/datetimepicker/calendar.html | 1 + .../datetimepicker-actions.component.html | 18 +++++++ .../datetimepicker-actions.component.scss | 4 ++ .../datetimepicker-actions.component.ts | 45 ++++++++++++++++ .../datetimepicker-content.html | 1 + .../datetimepicker-content.scss | 2 +- .../datetimepicker/datetimepicker.module.ts | 3 ++ .../core/src/datetimepicker/datetimepicker.ts | 52 ++++++++++++++++++- projects/core/src/datetimepicker/index.ts | 1 + 9 files changed, 124 insertions(+), 3 deletions(-) create mode 100644 projects/core/src/datetimepicker/datetimepicker-actions.component.html create mode 100644 projects/core/src/datetimepicker/datetimepicker-actions.component.scss create mode 100644 projects/core/src/datetimepicker/datetimepicker-actions.component.ts diff --git a/projects/core/src/datetimepicker/calendar.html b/projects/core/src/datetimepicker/calendar.html index 4d3fd89c..3bb124de 100644 --- a/projects/core/src/datetimepicker/calendar.html +++ b/projects/core/src/datetimepicker/calendar.html @@ -144,4 +144,5 @@ [twelvehour]="twelvehour" > + diff --git a/projects/core/src/datetimepicker/datetimepicker-actions.component.html b/projects/core/src/datetimepicker/datetimepicker-actions.component.html new file mode 100644 index 00000000..c660d621 --- /dev/null +++ b/projects/core/src/datetimepicker/datetimepicker-actions.component.html @@ -0,0 +1,18 @@ +
+ + +
diff --git a/projects/core/src/datetimepicker/datetimepicker-actions.component.scss b/projects/core/src/datetimepicker/datetimepicker-actions.component.scss new file mode 100644 index 00000000..35a07f06 --- /dev/null +++ b/projects/core/src/datetimepicker/datetimepicker-actions.component.scss @@ -0,0 +1,4 @@ +.mat-datetimepicker-actions { + display: flex; + justify-content: flex-end; +} diff --git a/projects/core/src/datetimepicker/datetimepicker-actions.component.ts b/projects/core/src/datetimepicker/datetimepicker-actions.component.ts new file mode 100644 index 00000000..26312fb8 --- /dev/null +++ b/projects/core/src/datetimepicker/datetimepicker-actions.component.ts @@ -0,0 +1,45 @@ +import { Component, Input } from '@angular/core'; + +import { + MatDatetimepickerComponent, + MatDatetimepickerContentComponent, +} from './datetimepicker'; + +@Component({ + selector: 'mat-datetimepicker-actions', + templateUrl: 'datetimepicker-actions.component.html', + styleUrls: ['datetimepicker-actions.component.scss'], +}) +export class MatDatetimepickerActionsComponent { + @Input() protected confirmButtonLabel = 'Confirm'; + @Input() protected cancelButtonLabel = 'Cancel'; + + private datetimepicker: MatDatetimepickerContentComponent; + + public fromTemplateWithDatetimepicker( + matDatetimepickerActions: MatDatetimepickerActionsComponent, + datetimepickerContent: MatDatetimepickerContentComponent + ) { + this.confirmButtonLabel = matDatetimepickerActions.confirmButtonLabel; + this.cancelButtonLabel = matDatetimepickerActions.cancelButtonLabel; + this.datetimepicker = datetimepickerContent; + datetimepickerContent._calendar._activeDate; + } + + protected handleCancelButton(event): void { + event.preventDefault(); + this.closeDatetimepicker(); + } + + protected handleConfirmButton(event): void { + event.preventDefault(); + this.datetimepicker.datetimepicker._select( + this.datetimepicker._calendar._activeDate + ); + this.closeDatetimepicker(); + } + + private closeDatetimepicker() { + this.datetimepicker.datetimepicker.close(); + } +} diff --git a/projects/core/src/datetimepicker/datetimepicker-content.html b/projects/core/src/datetimepicker/datetimepicker-content.html index bedd6ef0..3a8a766f 100644 --- a/projects/core/src/datetimepicker/datetimepicker-content.html +++ b/projects/core/src/datetimepicker/datetimepicker-content.html @@ -22,4 +22,5 @@ cdkTrapFocus class="mat-typography" > + diff --git a/projects/core/src/datetimepicker/datetimepicker-content.scss b/projects/core/src/datetimepicker/datetimepicker-content.scss index 751b9718..7c286610 100644 --- a/projects/core/src/datetimepicker/datetimepicker-content.scss +++ b/projects/core/src/datetimepicker/datetimepicker-content.scss @@ -5,8 +5,8 @@ $mat-datetimepicker-calendar-cell-size: 40px; $mat-datetimepicker-calendar-portrait-width: $mat-datetimepicker-calendar-cell-size * 7 + $mat-datetimepicker-calendar-padding * 2; $mat-datetimepicker-calendar-landscape-width: 446px; -$mat-datetimepicker-calendar-portrait-height: 405px; $mat-datetimepicker-calendar-landscape-height: 328px; +$mat-datetimepicker-calendar-portrait-height: 405px; .mat-datetimepicker-content { @include mat.elevation(8); diff --git a/projects/core/src/datetimepicker/datetimepicker.module.ts b/projects/core/src/datetimepicker/datetimepicker.module.ts index da8917e0..4a9c3bf2 100644 --- a/projects/core/src/datetimepicker/datetimepicker.module.ts +++ b/projects/core/src/datetimepicker/datetimepicker.module.ts @@ -10,6 +10,7 @@ import { MatDatetimepickerComponent, MatDatetimepickerContentComponent, } from './datetimepicker'; +import { MatDatetimepickerActionsComponent } from './datetimepicker-actions.component'; import { MatDatetimepickerInputDirective } from './datetimepicker-input'; import { MatDatetimepickerToggleComponent } from './datetimepicker-toggle'; import { MatDatetimepickerMonthViewComponent } from './month-view'; @@ -39,6 +40,7 @@ import { MatDialogModule } from '@angular/material/dialog'; MatDatetimepickerMonthViewComponent, MatDatetimepickerYearViewComponent, MatDatetimepickerMultiYearViewComponent, + MatDatetimepickerActionsComponent, ], exports: [ MatDatetimepickerCalendarComponent, @@ -51,6 +53,7 @@ import { MatDialogModule } from '@angular/material/dialog'; MatDatetimepickerMonthViewComponent, MatDatetimepickerYearViewComponent, MatDatetimepickerMultiYearViewComponent, + MatDatetimepickerActionsComponent, ], }) export class MatDatetimepickerModule {} diff --git a/projects/core/src/datetimepicker/datetimepicker.ts b/projects/core/src/datetimepicker/datetimepicker.ts index 1b4b9168..6c7cbd17 100644 --- a/projects/core/src/datetimepicker/datetimepicker.ts +++ b/projects/core/src/datetimepicker/datetimepicker.ts @@ -14,6 +14,7 @@ import { ChangeDetectionStrategy, Component, ComponentRef, + ContentChildren, EventEmitter, Inject, Input, @@ -21,6 +22,7 @@ import { OnDestroy, Optional, Output, + QueryList, ViewChild, ViewContainerRef, ViewEncapsulation, @@ -29,7 +31,7 @@ import { MAT_DATEPICKER_SCROLL_STRATEGY } from '@angular/material/datepicker'; import { MatDialog, MatDialogRef } from '@angular/material/dialog'; import { Subject, Subscription } from 'rxjs'; import { first } from 'rxjs/operators'; -import { DatetimeAdapter } from '../adapter/datetime-adapter'; +import { DatetimeAdapter } from '../adapter'; import { MatCalendarView, MatDatetimepickerCalendarComponent, @@ -38,6 +40,7 @@ import { createMissingDateImplError } from './datetimepicker-errors'; import { MatDatetimepickerFilterType } from './datetimepicker-filtertype'; import { MatDatetimepickerInputDirective } from './datetimepicker-input'; import { MatDatetimepickerType } from './datetimepicker-type'; +import { MatDatetimepickerActionsComponent } from './datetimepicker-actions.component'; export type MatDatetimepickerMode = 'auto' | 'portrait' | 'landscape'; @@ -69,10 +72,30 @@ export class MatDatetimepickerContentComponent implements AfterContentInit { @ViewChild(MatDatetimepickerCalendarComponent, { static: true }) _calendar: MatDatetimepickerCalendarComponent; + @ViewChild('matDatetimepickerActions', { + read: ViewContainerRef, + static: true, + }) + private viewRef: ViewContainerRef; + ngAfterContentInit() { this._calendar._focusActiveCell(); } + public renderActions( + matDatetimepickerActions: MatDatetimepickerActionsComponent + ): void { + this.viewRef.clear(); + const matDatetimepickerActionsComponent = this.viewRef.createComponent( + MatDatetimepickerActionsComponent + ); + matDatetimepickerActionsComponent.instance.fromTemplateWithDatetimepicker( + matDatetimepickerActions, + this + ); + matDatetimepickerActionsComponent.changeDetectorRef.detectChanges(); + } + onSelectionChange(date: D) { this.datetimepicker._select(date); this.datetimepicker.close(); @@ -99,7 +122,12 @@ export class MatDatetimepickerContentComponent implements AfterContentInit { encapsulation: ViewEncapsulation.None, preserveWhitespaces: false, }) -export class MatDatetimepickerComponent implements OnDestroy { +export class MatDatetimepickerComponent + implements AfterContentInit, OnDestroy +{ + @ContentChildren(MatDatetimepickerActionsComponent) + private actions: QueryList>; + /** Active multi year view when click on year. */ @Input() multiYearSelector: boolean = false; /** if true change the clock to 12 hour format. */ @@ -166,6 +194,12 @@ export class MatDatetimepickerComponent implements OnDestroy { } } + ngAfterContentInit(): void { + if (this.actions.length > 1) { + throw Error('Cannot have more than one actions children!'); + } + } + private _startAt: D | null; /** The date to open the calendar to initially. */ @@ -315,11 +349,13 @@ export class MatDatetimepickerComponent implements OnDestroy { if (this.opened || this.disabled) { return; } + if (!this._datepickerInput) { throw Error( 'Attempted to open an MatDatepicker with no associated input.' ); } + if (this._document) { this._focusedElementBeforeOpen = this._document.activeElement; } @@ -380,6 +416,8 @@ export class MatDatetimepickerComponent implements OnDestroy { }); this._dialogRef.afterClosed().subscribe(() => this.close()); this._dialogRef.componentInstance.datetimepicker = this; + + this.attachActionsIfPresent(this._dialogRef.componentInstance); } /** Open the calendar as a popup. */ @@ -399,6 +437,8 @@ export class MatDatetimepickerComponent implements OnDestroy { this._popupRef.attach(this._calendarPortal); componentRef.instance.datetimepicker = this; + this.attachActionsIfPresent(componentRef.instance); + // Update the position once the calendar has rendered. this._ngZone.onStable .asObservable() @@ -461,4 +501,12 @@ export class MatDatetimepickerComponent implements OnDestroy { }, ]); } + + private attachActionsIfPresent( + componentInstance: MatDatetimepickerContentComponent + ) { + if (this.actions.length === 1) { + componentInstance.renderActions(this.actions.get(0)); + } + } } diff --git a/projects/core/src/datetimepicker/index.ts b/projects/core/src/datetimepicker/index.ts index 3125577e..7c710e80 100644 --- a/projects/core/src/datetimepicker/index.ts +++ b/projects/core/src/datetimepicker/index.ts @@ -3,6 +3,7 @@ export * from './clock'; export * from './calendar'; export * from './calendar-body'; export * from './datetimepicker'; +export * from './datetimepicker-actions.component'; export * from './datetimepicker-filtertype'; export * from './datetimepicker-input'; export * from './datetimepicker-toggle'; From 046377470dd1806de41a239f00c0516093cd0fa0 Mon Sep 17 00:00:00 2001 From: Timon Borter Date: Wed, 15 Mar 2023 18:10:06 +0100 Subject: [PATCH 2/2] docs(#163): action button sample add an action button sample to the application. also document its usage in `README.md`. --- README.md | 12 +++++++ src/app/date.component.html | 70 ++++++++++++++++++++++++------------- 2 files changed, 58 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index 9931400e..fa98cafd 100644 --- a/README.md +++ b/README.md @@ -80,6 +80,18 @@ imports: [ ``` +You can optionally add action buttons inside the `mat-datetimepicker`. + +```html + + + + +``` + ## Date formatting In order to change the default input/output formats, a custom instance of `MAT_DATETIME_FORMATS` needs to be provided in diff --git a/src/app/date.component.html b/src/app/date.component.html index 128cc85a..917710ab 100644 --- a/src/app/date.component.html +++ b/src/app/date.component.html @@ -25,14 +25,14 @@

required /> required + >required + min + >min + max + >max + placeholder="DateTime Year selector" /> required + >required + min + >min + max + >max + placeholder="Time AM/PM" /> required + >required + type="datetime" > required + >required + min + >min + max + >max + type="datetime" > required + >required + filter + >filter + type="datetime" > + + + + + + +