Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular material today button

My task is to put a today button on angular datepicker popup. (Selects the today date and closes popup)

<input matInput [matDatepicker]="toPicker" formControlName="validTo" >
<mat-datepicker-toggle matSuffix [for]="toPicker"></mat-datepicker-toggle>
<mat-datepicker #toPicker  >
   <mat-datepicker-actions>
    <button mat-button (click)="goToday()">Today</button>
  </mat-datepicker-actions> 
</mat-datepicker>

The angular function:

    @ViewChild('toPicker') toPicker: MatDatepicker<Date>;
  goToday() {
    this.toPicker.select(new Date());
    this.toPicker.close();
  }

This works! Unfortunately the default date selection is broken. I can click on a date but the popup remains open. Do you have idea how to add a today button and preserve the default funcionality

like image 788
Géza Avatar asked Apr 10 '26 11:04

Géza


1 Answers

If anyone else encounters the same problem, I solved it by using the material overlay from CDK in combination with a mat-calendar. This approach offers much greater flexibility.

 <div
  class="flex items-center rounded-full bg-white text-black cursor-pointer px-3 py-1 mr-4"
  data-test="datepickerBtn"
  type="button"
  cdkOverlayOrigin
  #trigger="cdkOverlayOrigin"
  (click)="isOpen = !isOpen"
>
  <mat-hint>
    @if (isTodaySelected) {
      Today
    } @else {
      {{ selectedDate | date }}
    }
  </mat-hint>
  <mat-icon class="ml-1.5">event</mat-icon>
  <ng-template
    cdkConnectedOverlay
    [cdkConnectedOverlayPositions]="[position]"
    [cdkConnectedOverlayOffsetY]="5"
    [cdkConnectedOverlayOrigin]="trigger"
    [cdkConnectedOverlayOpen]="isOpen"
    (overlayOutsideClick)="isOpen = false"
  >
    <mat-card class="w-80 rounded-xl">
      <mat-calendar
        #calendar
        (selectedChange)="onSelectDate($event)"
        [startAt]="selectedDate"
        [selected]="selectedDate"
      />
      <div class="w-full flex justify-center mb-3">
        <button mat-button color="primary" (click)="onSelectDate()">
          Today
        </button>
      </div>
    </mat-card>
  </ng-template>
</div>

Component:

import { ConnectedPosition, OverlayModule } from '@angular/cdk/overlay';
import { CommonModule } from '@angular/common';
import { Component, EventEmitter, Input, Output } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { MatCardModule } from '@angular/material/card';
import { MatDatepickerModule } from '@angular/material/datepicker';
import { MatIconModule } from '@angular/material/icon';
import { MatInputModule } from '@angular/material/input';
import { TranslocoModule } from '@ngneat/transloco';
import { isSameDay } from 'date-fns';

@Component({
  selector: 'coa-org-datepicker',
  standalone: true,
  imports: [
    CommonModule,
    MatInputModule,
    MatDatepickerModule,
    MatIconModule,
    MatButtonModule,
    TranslocoModule,
    MatCardModule,
    OverlayModule,
  ],
  templateUrl: './datepicker.component.html',
})
export class DatepickerComponent {
  @Input() selectedDate: Date = new Date();
  @Output() dateSelected = new EventEmitter<Date>();

  isOpen = false;

  position: ConnectedPosition = {
    originX: 'end',
    originY: 'bottom',
    overlayX: 'end',
    overlayY: 'top',
  };

  onSelectDate(date: Date = new Date()): void {
    this.isOpen = false;
    this.dateSelected.emit(date);
  }

  get isTodaySelected() {
    return isSameDay(this.selectedDate, new Date());
  }
}

ConnectedPosition is only necessary if you don't want the overlay to attach to the bottom-left corner of your origin element. The div with the cdkOverlayOrigin directive can be any HTML element, such as a button, input, or any other element.

Here are the docs for the overlay part:

https://material.angular.io/cdk/overlay/api

This example also uses tailwind for css classes.

like image 174
J. S. Avatar answered Apr 13 '26 09:04

J. S.