A comprehensive package providing separate DatePicker and TimePicker components for Angular applications, with support for both Jalali (Persian) and Gregorian calendars. This package supports Angular 14 and above. Specific version compatibility:
Package Version | Angular Version |
---|---|
1.x.x | ≥14.0.0 |
You can see the online Demo
This package includes two main components:
-
QeydarDatePicker
: A flexible date picker with range selection support and time selection -
QeydarTimePicker
: A standalone time picker with 12/24 hour format support
- 📅 Support for both Jalali (Persian) and Gregorian calendars
- 🎯 Single date and date range selection
- ⏰ Integrated time selection support
- 🌐 Multilingual support (English/Persian)
- 📏 Min/Max date restrictions
- 🎨 Customizable styles
- 📱 Responsive design
- ⌨️ Keyboard navigation
- 🔄 Form integration
- 📋 Custom period labels
- 📐 Multiple placement options
- 🔄 Value format flexibility (string/Date object)
- 🎯 Today button support
- 🚫 Disabled dates support with custom filtering
- 🎨 Custom templates for days, months, and years
- 🔒 Read-only mode support
- ⏰ 12/24 hour format support
- ⏱️ Optional seconds display
- 🔒 Time range restrictions
- 🎭 Time input mask
- 🌐 Multilingual AM/PM
- 📍 Inline display mode
- 🔄 Date adapter integration
- 🚫 Disabled times support with custom filtering
npm install @angular/cdk@<COMPATIBLE_VERSION> @qeydar/datepicker
{
"@angular/cdk": ">=14.0.0",
"date-fns": ">=2.0.0",
"date-fns-jalali": ">=2.13.0"
}
@import '@angular/cdk/overlay-prebuilt.css';
// app.module.ts
import { QeydarDatepickerModule } from '@qeydar/datepicker';
@NgModule({
imports: [QeydarDatepickerModule]
})
export class AppModule { }
// component.ts
@Component({
template: `
<qeydar-date-picker
[(ngModel)]="selectedDate"
[calendarType]="'jalali'"
></qeydar-date-picker>
`
})
export class AppComponent {
selectedDate: Date | string = '1403/01/01'; // Can accept both Date object and string
}
The DatePicker supports flexible range selection with multiple ways to handle values:
@Component({
template: `
<qeydar-date-picker
[(ngModel)]="dateRange"
[isRange]="true"
[rangeInputLabels]="{ start: 'From', end: 'To' }"
[emitInDateFormat]="false"
[calendarType]="'jalali'"
></qeydar-date-picker>
`
})
export class AppComponent {
// Using string values
dateRange = {
start: '1403/08/12',
end: '1403/08/15'
};
// Using mixed values (string and Date)
dateRange2 = {
start: '1403/08/12',
end: new Date()
};
// Using Date objects
dateRange3 = {
start: new Date('2024-01-01'),
end: new Date('2024-01-07')
};
// With emitInDateFormat=true, values will be emitted as Date objects
onRangeChange(range: { start: Date, end: Date }) {
console.log('Start:', range.start);
console.log('End:', range.end);
}
}
// Define custom period labels
const customLabels: CustomLabels[] = [
{
label: 'This Week',
value: [new Date('2024-01-01'), new Date('2024-01-07')]
},
{
label: 'Last 7 Days',
value: ['1403/08/05', '1403/08/12'] // Can use strings for Jalali dates
},
{
label: 'Custom Range',
value: 'custom'
}
];
@Component({
template: `
<qeydar-date-picker
[(ngModel)]="dateRange"
[isRange]="true"
[customLabels]="customLabels"
(onChangeValue)="onRangeChange($event)"
></qeydar-date-picker>
`
})
@Component({
template: `
<qeydar-date-picker
[(ngModel)]="selectedDateTime"
[format]="'yyyy/MM/dd HH:mm:ss'"
[showTimePicker]="true"
[timeDisplayFormat]="'HH:mm'"
[showToday]="true"
></qeydar-date-picker>
`
})
export class AppComponent {
selectedDateTime: Date | string = new Date();
}
@Component({
template: `
<qeydar-date-picker
[(ngModel)]="selectedDate"
[valueFormat]="'gregorian'" // 'gregorian' | 'jalali' | 'date'
[calendarType]="'jalali'"
></qeydar-date-picker>
`
})
@Component({
template: `
<qeydar-date-picker
[(ngModel)]="selectedDate"
[disabledDates]="disabledDates"
[disabledDatesFilter]="disabledDatesFilter"
></qeydar-date-picker>
`
})
export class AppComponent {
// These will disable the entire day
disabledDates = [
new Date(2024, 0, 1), // Jan 1, 2024
new Date(2024, 11, 25), // Dec 25, 2024
'2024/01/15' // Jan 15, 2024
];
// This will disable specific days advanced
disabledDatesFilter = (date: Date) => {
const day = date.getDay();
return day === 0 || day === 6; // Disable weekends
};
}
The DatePicker now supports custom templates for days, months, and years, allowing you to customize how these elements are rendered:
@Component({
template: `
<qeydar-date-picker [(ngModel)]="selectedDate">
<!-- Custom day template -->
<ng-template qeydarTemplate="day" let-day>
<div class="custom-day">
{{ day.getDate() }}
<!-- Add custom indicators or styling -->
<span *ngIf="isSpecialDay(day)" class="special-indicator">*</span>
</div>
</ng-template>
<!-- Custom month template -->
<ng-template qeydarTemplate="month" let-month>
<div class="custom-month">
{{ getMonthName(month) }}
<!-- Add custom content -->
</div>
</ng-template>
<!-- Custom year template -->
<ng-template qeydarTemplate="year" let-year>
<div class="custom-year">
{{ year }}
<!-- Add custom styling or indicators -->
</div>
</ng-template>
</qeydar-date-picker>
`
})
export class AppComponent {
isSpecialDay(date: Date): boolean {
// Your custom logic
return date.getDate() === 1;
}
}
The DatePicker now supports two types of read-only modes:
@Component({
template: `
<!-- Completely read-only - prevents both input and calendar interaction -->
<qeydar-date-picker
[(ngModel)]="selectedDate"
[readOnly]="true"
></qeydar-date-picker>
<!-- Read-only input but allows calendar interaction -->
<qeydar-date-picker
[(ngModel)]="selectedDate"
[readOnlyInput]="true"
></qeydar-date-picker>
`
})
The TimePicker is a separate component for time selection:
@Component({
template: `
<qeydar-time-picker
[(ngModel)]="selectedTime"
[timeFormat]="'24'"
[showSeconds]="true"
[minTime]="'09:00'"
[maxTime]="'17:00'"
></qeydar-time-picker>
`
})
export class AppComponent {
selectedTime = '14:30:00';
// Or using Date object with valueType="date"
selectedDateTime = new Date();
}
<qeydar-time-picker
[(ngModel)]="time"
[timeFormat]="'12'"
[displayFormat]="'hh:mm a'"
[rtl]="true"
(timeChange)="onTimeChange($event)"
></qeydar-time-picker>
@Component({
template: `
<qeydar-time-picker
[(ngModel)]="time"
[inline]="true"
[dateAdapter]="dateAdapter"
[timeDisplayFormat]="'HH:mm:ss'"
(timeChange)="onTimeChange($event)"
></qeydar-time-picker>
`,
})
export class AppComponent {
constructor(public dateAdapter: GregorianDateAdapter) {}
}
@Component({
template: `
<qeydar-time-picker
[(ngModel)]="selectedTime"
[disabledTimesFilter]="disabledTimesFilter"
></qeydar-time-picker>
`
})
export class AppComponent {
// Disable lunch hours (12:00-13:00)
disabledTimesFilter = (date: Date) => {
const hour = date.getHours();
const minute = date.getMinutes();
// Disable specific hour
if (hour === 12) return true;
// Disable specific minutes
if (minute === 45) return true;
return false;
}
}
Input | Type | Default | Description |
---|---|---|---|
rtl | boolean | false | Right-to-left mode |
mode | 'day' | 'month' | 'year' | 'day' | Selection mode |
isRange | boolean | false | Enable range selection |
format | string | 'yyyy/MM/dd' | Date format |
calendarType | 'jalali' | 'gregorian' | 'gregorian' | Calendar type |
minDate | Date | null | Minimum selectable date |
maxDate | Date | null | Maximum selectable date |
cssClass | string | '' | Custom CSS class |
footerDescription | string | '' | Footer description text |
rangeInputLabels | RangeInputLabels | undefined | Labels for range inputs |
inputLabel | string | undefined | Label for single input |
placement | Placement | 'bottomLeft' | Dropdown placement |
disabled | boolean | false | Disable the datepicker |
isInline | boolean | false | Show calendar inline |
showSidebar | boolean | true | Show sidebar with months/years |
showToday | boolean | false | Highlight today's date |
valueFormat | 'gregorian' | 'jalali' | 'date' | 'gregorian' | Output value format |
disableInputMask | boolean | false | To disable input mask |
disabledDates | Arrar<Date | string> | |
disabledDatesFilter | (date: Date) => boolean | undefined | Function to determine if a date should be disabled |
disabledTimesFilter | (date: Date) => boolean | undefined | Function to determine if a time of date should be disabled |
allowEmpty | boolean | true | Allow empty value |
readOnly | boolean | false | Make the entire component read-only |
readOnlyInput | boolean | false | Make only the input field read-only |
Output | Type | Description |
---|---|---|
onFocus | EventEmitter | Fires when input receives focus |
onBlur | EventEmitter | Fires when input loses focus |
onChangeValue | EventEmitter | Fires when value changes |
onOpenChange | EventEmitter | Fires when picker opens/closes |
Input | Type | Default | Description |
---|---|---|---|
placeholder | string | 'Select time' | Input placeholder |
displayFormat | string | 'hh:mm a' | Time display format |
minTime | string | undefined | Minimum selectable time |
maxTime | string | undefined | Maximum selectable time |
valueType | 'string' | 'date' | 'string' | Output value type |
cssClass | string | '' | Custom CSS class |
showIcon | boolean | true | Show clock icon |
rtl | boolean | false | Right-to-left mode |
lang | Lang_Locale | lang_En | Language settings |
inline | boolean | false | Show time picker inline (without popup) |
dateAdapter | DateAdapter | undefined | Custom date adapter for time manipulation |
disableInputMask | boolean | false | To disable input mask |
disabledTimesFilter | (date: Date) => boolean | undefined | Function to determine if a time should be disabled |
disabled | boolean | false | Disable the time picker |
allowEmpty | boolean | true | Allow empty value |
readOnly | boolean | false | Make the entire component read-only |
readOnlyInput | boolean | false | Make only the input field read-only |
Output | Type | Description |
---|---|---|
timeChange | EventEmitter | Fires when time changes |
openChange | EventEmitter | Fires when picker opens/closes |
@Component({
template: `
<form [formGroup]="form">
<!-- Date Range -->
<qeydar-date-picker
formControlName="dateRange"
[isRange]="true"
[calendarType]="'jalali'"
></qeydar-date-picker>
<!-- Time -->
<qeydar-time-picker
formControlName="time"
[timeFormat]="'24'"
></qeydar-time-picker>
</form>
`
})
export class AppComponent {
form = this.fb.group({
dateRange: [{
start: '1403/08/12',
end: new Date()
}],
time: ['14:30']
});
constructor(private fb: FormBuilder) {}
}
<qeydar-time-picker
[(ngModel)]="time"
[inline]="true"
[timeFormat]="'24'"
[displayFormat]="'HH:mm:ss'"
></qeydar-time-picker>
The TimePicker automatically adapts to your chosen calendar system:
// Jalali (Persian) Time Picker
<qeydar-time-picker
[(ngModel)]="time"
[rtl]="true"
[timeFormat]="'12'"
></qeydar-time-picker>
// Gregorian Time Picker
<qeydar-time-picker
[(ngModel)]="time"
[rtl]="false"
[timeFormat]="'24'"
></qeydar-time-picker>
<form #form="ngForm">
<qeydar-date-picker
[(ngModel)]="dateRange"
name="dateRange"
[isRange]="true"
required
></qeydar-date-picker>
<qeydar-time-picker
[(ngModel)]="time"
name="time"
required
></qeydar-time-picker>
</form>
Both components can be styled using CSS variables:
.qeydar-time-picker {
--primary-color: #40a9ff;
--border-color: #d9d9d9;
--text-color: #666;
--background-color: white;
--hover-background: #f5f5f5;
--selected-background: #e6f4ff;
--selected-text-color: #1890ff;
--disabled-color: #d9d9d9;
}
/* Inline mode specific styles */
.time-picker-popup.inline {
border: 1px solid var(--border-color);
border-radius: 8px;
}
Contributions are welcome! Please feel free to submit a Pull Request.
MIT License