Let’s look at how to implement the Angular selection range for the newest Angular PrimeNg version. This tutorial was developed on v10.0.0-rc-1 version.
I had difficulty finding a proper solution for range selection in the PrimeNg turbo data table for the newest version. Therefore I have decided to create a workaround. For the time selection, each click event on the calendar panel fire only one piece of data – the currently selected date. So the calendar range is stateless. You need to remember somehow to keep in memory what date was fired before and implement this logic in a custom filter.
I observed that there are several rules according to which p-calendar
component behave when the selection mode "range"
is selected. Here are my findings according to which I programmed the logic:
- At first, the calendar component has an empty, undefined selection.
- If one date is selected, only one date is fired on click event.
- If the same date as date previously selected is selected, new date (which is the same as previously selected date) is fired on click event.
- If a date before the already selected date is selected, the selection is cancelled and earlier date is fired on click event.
- If a date after the already selected date is selected, the selection range is visible.
- If any new date is selected after the selection range is visible, a new date is selected, fired upon click event and selection range is cancelled.
When all this wrote down, here is the implementation code for component and custom filter:
record-list.component.html
<p-table #dt [value]="records" sortMode="multiple" [paginator]="true" [rowsPerPageOptions]="rowsPerPageTable" [rows]="rowsPerTable" [showCurrentPageReport]="true" [(first)]="page" styleClass="p-datatable-striped" currentPageReportTemplate="Showing {first} to {last} of {totalRecords} entries">
<ng-template pTemplate="header">
<tr class="ui-table-thead">
<th [ngStyle]="{'width':'50%'}" pSortableColumn="createdDate">Created <p-sortIcon field="createdDate"></p-sortIcon></th>
<th [ngStyle]="{'width':'50%'}" pSortableColumn="info">Info <p-sortIcon field="info"></p-sortIcon></th>
</tr>
<tr class="ui-table-thead">
<th scope="col">
<p-calendar (onSelect)="onDateSelect($event)" [style]="{'width':'100%'}" selectionMode="range" [readonlyInput]="true" (onClearClick)="onDateClear($event)" [showButtonBar]="true" placeholder="Created Date" class="p-column-filter" dateFormat="yy-mm-dd"></p-calendar>
</th>
<th scope="col">
<input pInputText type="text" [style]="{'width':'100%'}" (input)="dt.filter($event.target.value, 'info', 'contains')" placeholder="Info">
</th>
</tr>
</ng-template>
<ng-template pTemplate="body" let-rowData>
<tr ng-repeat="rowData in let-rowData" ng-click="showClient(rowData)">
<td>{{ rowData.createdDate }}</td>
<td>{{ rowData.info }}</td>
</tr>
</ng-template>
</p-table>
record-list.component.ts
export class RecordListComponent implements OnInit {
public records: IssueShortInfo[];
@ViewChild('dt') table: Table;
cols: any[];
dateRangeStart: string;
dateRangeEnd: string;
rowsPerPageTable: number[] = [25, 50, 100, 200];
page: number = 0;
rowsPerTable: number = 25;
constructor(private recordService: RecordService) {}
ngOnInit() {
this.recordService.getAllRecords().subscribe(page => {
this.getRecords(page);
}, (error => {
console.log(error)
}));
this.cols = [
{field: 'id', header: 'Id'},
{field: 'createdDate', header: 'Created Date'},
{field: 'info', header: 'Info'}
];
FilterUtils['customCreatedDateFilter'] = (value: string, filter) => {
if (this.dateRangeStart === value && this.dateRangeEnd === undefined) {
return true;
}
if (this.dateRangeStart === value || this.dateRangeEnd === value) {
return true;
}
if (this.dateRangeStart !== undefined && this.dateRangeEnd !== undefined &&
moment(this.dateRangeStart).isBefore(value) && moment(this.dateRangeEnd).isAfter(value)) {
return true;
}
return false;
};
}
getRecords(page: Page) {
this.records = page.content.map(incomingRecordDTO => new Record(incomingRecordDTO));
}
onDateSelect($event) {
const eventDate = this.formatDate($event);
if (this.dateRangeStart === undefined) {
this.dateRangeStart = eventDate;
} else if (moment($event).isBefore(this.dateRangeStart)) {
this.dateRangeStart = eventDate;
this.dateRangeEnd = undefined;
} else if (moment($event).isSame(this.dateRangeStart) && this.dateRangeStart !== undefined && this.dateRangeEnd === undefined) {
this.dateRangeEnd = eventDate;
} else if (moment($event).isSame(this.dateRangeStart) && this.dateRangeStart !== undefined && this.dateRangeEnd !== undefined) {
this.dateRangeStart = eventDate;
this.dateRangeEnd = undefined;
} else if (moment($event).isAfter(this.dateRangeStart) && this.dateRangeStart !== undefined && this.dateRangeEnd !== undefined) {
this.dateRangeStart = eventDate;
this.dateRangeEnd = undefined;
} else {
this.dateRangeEnd = eventDate;
}
this.table.filter(eventDate, 'createdDate', 'customCreatedDateFilter');
}
onDateClear($event) {
this.dateRangeStart = undefined;
this.dateRangeEnd = undefined;
this.table.filter('', 'createdDate', 'equals');
}
formatDate(date) {
let month = date.getMonth() + 1;
let day = date.getDate();
if (month < 10) {
month = '0' + month;
}
if (day < 10) {
day = '0' + day;
}
return date.getFullYear() + '-' + month + '-' + day;
}
customCreatedDateArrayFilter(event) {
this.table.filter(event, 'createdDate', 'customCreatedDateFilter');
}
}
Thanks for sharing, I was looking for a solution like this