I am creating a flexible filter based on a datePicker that allows users to select a specific date, a range, a month, or a year. This is my current work in progress. While it functions to some extent, I am not satisfied with its appearance.
Go to Updated section, skip this first attempt
My goal is to display a single input showing the current value, similar to other filters (for example, the amount column in the provided image). I attempted to add an input manually because, without it, only a button with a calendar icon is shown. However, the standalone input field appears different. Although I could invest time in CSS adjustments, I don't find that approach ideal.
The default input filter is displayed within the popover, meaning I end up with two inputs. Is there a way to maintain a standard filter look and feel while customizing the picker (for example, to allow switching between various input types)?
I believe that having multiple instances of the datePicker is not optimal—instead, I should have a single element that I customize on the fly. This issue stems from using tabs. Is there a better method to handle this switching functionality?
Here is a demo: https://stackblitz.com/edit/literakl-primeng-flexible-date-filter?file=src%2Fapp%2Fgrid%2Fgrid.component.html
<p-columnFilter field="settledAt" type="date" [matchModeOptions]="dateMatchModeOptions" [showClearButton]="false">
<ng-template pTemplate="filter" let-value let-filter="filterCallback">
<div class="datepicker-filter">
<input [(ngModel)]="displayDate" (click)="popover.toggle($event)" placeholder="Select date" readonly>
<p-popover #popover [dismissable]="true">
<p-tabView>
<p-tabPanel header="Single Day">
<p-datePicker [(ngModel)]="singleDate" dateFormat="mm/dd/yy" appendTo="body" (ngModelChange)="onSingleDateChange(filter, singleDate)"></p-datePicker>
</p-tabPanel>
<p-tabPanel header="Date Range">
<p-datePicker [(ngModel)]="rangeDates" selectionMode="range" dateFormat="mm/dd/yy" appendTo="body" (ngModelChange)="onDateRangeChange(filter, rangeDates)"></p-datePicker>
</p-tabPanel>
<p-tabPanel header="Month">
<p-datePicker [(ngModel)]="monthDate" view="month" dateFormat="MM yy" appendTo="body" (ngModelChange)="onMonthChange(filter, monthDate)"></p-datePicker>
</p-tabPanel>
<p-tabPanel header="Year">
<p-datePicker [(ngModel)]="yearDate" view="year" dateFormat="yy" appendTo="body" (ngModelChange)="onYearChange(filter, yearDate)"></p-datePicker>
</p-tabPanel>
</p-tabView>
</p-popover>
</div>
</ng-template>
</p-columnFilter>
Update
Though this solution was working, the UX was bad, because of duplicated input field and neccessity to click twice to open the date picker. I realized the date picker has a head template where I can put buttons. I was able to implement it and it looked fine.
The trouble was when I switched from Day mode to other modes like Month or Year. Selecting month worked fine, but when I closed the date picker and reopened it, the date picker width was reduced, all padding was gone. When switching back to Date, two overlapping boxes were displayed. When I selected a sigle date, closed the dialog and reopened it, it just started to work again, until I selected a period.
StackBlitz demonstrates the issue but not so dramatically like in a real project where I have many columns.
<p-datePicker
[(ngModel)]="singleDate"
(ngModelChange)="onSingleDateChange(filter, singleDate)"
(onFocus)="onTimePickerFocus($event)"
[dateFormat]="getTimePickerFormat()"
[view]="getTimePickerMode()"
[selectionMode]="getTimePickerSelectionMode()"
showClear="true"
[readonlyInput]="true"
[showButtonBar]="true"
[showIcon]="true"
[showClear]="false"
appendTo="body"
[fluid]="true"
>
<ng-template pTemplate="header">
<p-selectButton
[options]="dateTypeOptions"
[(ngModel)]="selectedDateType"
(onChange)="onDateTypeChange($event.value)"
>
</p-selectButton>
</ng-template>
</p-datePicker>
How to fix it please?
Use panelStyle
prop to adjust the width of the datepicker container. If you set the width to min-content
then there will not be any overflowing content in the datepicker container. So switching between the Date and Month selection will not alter the width of the datepicker.
[panelStyle]="{ width: 'min-content' }"
Checkout this working Stackblitz demo.
Full code:
<p-datePicker
[(ngModel)]="singleDate"
(ngModelChange)="onSingleDateChange(filter, singleDate)"
(onFocus)="onTimePickerFocus($event)"
[dateFormat]="getTimePickerFormat()"
[view]="getTimePickerMode()"
[selectionMode]="getTimePickerSelectionMode()"
showClear="true"
[readonlyInput]="true"
[showButtonBar]="true"
[showIcon]="true"
[showClear]="false"
appendTo="body"
[fluid]="true"
[panelStyle]="{ width: 'min-content' }"
>
<ng-template pTemplate="header">
<p-selectButton
[options]="dateTypeOptions"
[(ngModel)]="selectedDateType"
(onChange)="onDateTypeChange($event.value)"
>
</p-selectButton>
</ng-template>
</p-datePicker>