تاریخچهی تغییرات کامپوننت Date-Picker
DateAdapter شمسی تهیه شده از کتابخانهی jalali-moment برای تبدیل تاریخها استفاده میکند. بنابراین ابتدا نیاز است این وابستگی را نصب کرد:
npm install jalali-moment --save
افزودن DateAdapter شمسی به پروژه
برای افزودن DateAdapter شمسی تهیه شده، فایل جدید app\shared\material.persian-date.adapter.ts را به برنامه اضافه کرده و به صورت زیر تکمیل کنید:
import { DateAdapter } from "@angular/material"; import * as jalaliMoment from "jalali-moment"; export const PERSIAN_DATE_FORMATS = { parse: { dateInput: "jYYYY/jMM/jDD" }, display: { dateInput: "jYYYY/jMM/jDD", monthYearLabel: "jYYYY jMMMM", dateA11yLabel: "jYYYY/jMM/jDD", monthYearA11yLabel: "jYYYY jMMMM" } }; export class MaterialPersianDateAdapter extends DateAdapter<jalaliMoment.Moment> { constructor() { super(); super.setLocale("fa"); } getYear(date: jalaliMoment.Moment): number { return this.clone(date).jYear(); } getMonth(date: jalaliMoment.Moment): number { return this.clone(date).jMonth(); } getDate(date: jalaliMoment.Moment): number { return this.clone(date).jDate(); } getDayOfWeek(date: jalaliMoment.Moment): number { return this.clone(date).day(); } getMonthNames(style: "long" | "short" | "narrow"): string[] { switch (style) { case "long": case "short": return jalaliMoment.localeData("fa").jMonths().slice(0); case "narrow": return jalaliMoment.localeData("fa").jMonthsShort().slice(0); } } getDateNames(): string[] { const valuesArray = Array(31); for (let i = 0; i < 31; i++) { valuesArray[i] = String(i + 1); } return valuesArray; } getDayOfWeekNames(style: "long" | "short" | "narrow"): string[] { switch (style) { case "long": return jalaliMoment.localeData("fa").weekdays().slice(0); case "short": return jalaliMoment.localeData("fa").weekdaysShort().slice(0); case "narrow": return ["ی", "د", "س", "چ", "پ", "ج", "ش"]; } } getYearName(date: jalaliMoment.Moment): string { return this.clone(date).jYear().toString(); } getFirstDayOfWeek(): number { return jalaliMoment.localeData("fa").firstDayOfWeek(); } getNumDaysInMonth(date: jalaliMoment.Moment): number { return this.clone(date).jDaysInMonth(); } clone(date: jalaliMoment.Moment): jalaliMoment.Moment { return date.clone().locale("fa"); } createDate(year: number, month: number, date: number): jalaliMoment.Moment { if (month < 0 || month > 11) { throw Error( `Invalid month index "${month}". Month index has to be between 0 and 11.` ); } if (date < 1) { throw Error(`Invalid date "${date}". Date has to be greater than 0.`); } const result = jalaliMoment() .jYear(year).jMonth(month).jDate(date) .hours(0).minutes(0).seconds(0).milliseconds(0) .locale("fa"); if (this.getMonth(result) !== month) { throw Error(`Invalid date ${date} for month with index ${month}.`); } if (!result.isValid()) { throw Error(`Invalid date "${date}" for month with index "${month}".`); } return result; } today(): jalaliMoment.Moment { return jalaliMoment().locale("fa"); } parse(value: any, parseFormat: string | string[]): jalaliMoment.Moment | null { if (value && typeof value === "string") { return jalaliMoment(value, parseFormat, "fa"); } return value ? jalaliMoment(value).locale("fa") : null; } format(date: jalaliMoment.Moment, displayFormat: string): string { date = this.clone(date); if (!this.isValid(date)) { throw Error("JalaliMomentDateAdapter: Cannot format invalid date."); } return date.format(displayFormat); } addCalendarYears(date: jalaliMoment.Moment, years: number): jalaliMoment.Moment { return this.clone(date).add(years, "jYear"); } addCalendarMonths(date: jalaliMoment.Moment, months: number): jalaliMoment.Moment { return this.clone(date).add(months, "jmonth"); } addCalendarDays(date: jalaliMoment.Moment, days: number): jalaliMoment.Moment { return this.clone(date).add(days, "jDay"); } toIso8601(date: jalaliMoment.Moment): string { return this.clone(date).format(); } isDateInstance(obj: any): boolean { return jalaliMoment.isMoment(obj); } isValid(date: jalaliMoment.Moment): boolean { return this.clone(date).isValid(); } invalid(): jalaliMoment.Moment { return jalaliMoment.invalid(); } deserialize(value: any): jalaliMoment.Moment | null { let date; if (value instanceof Date) { date = jalaliMoment(value); } if (typeof value === "string") { if (!value) { return null; } date = jalaliMoment(value).locale("fa"); } if (date && this.isValid(date)) { return date; } return super.deserialize(value); } }
پس از تعریف MaterialPersianDateAdapter و همچنین PERSIAN_DATE_FORMATS، برای معرفی آنها به برنامه، فایل app\shared\material.module.ts را گشوده و به صورت زیر تغییر دهید:
import { NgModule } from "@angular/core"; import { DateAdapter, MAT_DATE_FORMATS, MAT_DATE_LOCALE } from "@angular/material"; import { MaterialPersianDateAdapter, PERSIAN_DATE_FORMATS } from "./material.persian-date.adapter"; @NgModule({ providers: [ { provide: DateAdapter, useClass: MaterialPersianDateAdapter, deps: [MAT_DATE_LOCALE] }, { provide: MAT_DATE_FORMATS, useValue: PERSIAN_DATE_FORMATS } ] }) export class MaterialModule { }
پس از آن اگر mat-datepicker را به نحو متداولی به صفحه اضافه کنیم:
<mat-form-field> <input matInput [matDatepicker]="picker6" placeholder="json gregorian input" [(ngModel)]="dateControl"> <mat-datepicker-toggle matSuffix [for]="picker6"></mat-datepicker-toggle> <mat-datepicker #picker6></mat-datepicker> </mat-form-field>
چند مثال تکمیلی از کاربردهای کامپوننت mat-datepicker
1) استفاده از تاریخ میلادی رسیدهی از سمت سرور و نمایش آن
<mat-form-field> <input matInput [matDatepicker]="picker6" placeholder="json gregorian input" [(ngModel)]="dateControl"> <mat-datepicker-toggle matSuffix [for]="picker6"></mat-datepicker-toggle> <mat-datepicker #picker6></mat-datepicker> </mat-form-field>
@Component() export class PersianDatepickerComponent { jsonDate = "2018-01-08T20:21:29.4674496"; dateControl = this.jsonDate; }
2) تعیین تاریخ آغاز تقویم و نمایش آن در حالت انتخاب سال
<mat-form-field> <input matInput [matDatepicker]="picker2" placeholder="startAt 2017-01-01 and startView=year"> <mat-datepicker-toggle matSuffix [for]="picker2"></mat-datepicker-toggle> <mat-datepicker #picker2 startView="year" [startAt]="startDate"></mat-datepicker> </mat-form-field>
import * as moment from "jalali-moment"; @Component() export class PersianDatepickerComponent { startDate = moment("2017-01-01", "YYYY-MM-DD"); // = moment.from("2017-01-01", "en"); }
3) تعیین بازهی تاریخی قابل انتخاب توسط کاربر
<mat-form-field> <input matInput [matDatepicker]="picker3" [min]="minDate" [max]="maxDate" placeholder="min: 2017-10-02 and max: 1396-07-29"> <mat-datepicker-toggle matSuffix [for]="picker3"></mat-datepicker-toggle> <mat-datepicker #picker3></mat-datepicker> </mat-form-field>
import * as moment from "jalali-moment"; @Component() export class PersianDatepickerComponent { minDate = moment.from("2017-10-02", "en"); // = moment('2017-10-02', 'YYYY-MM-DD'); maxDate = moment.from("1396-07-29", "fa"); // = moment('1396-07-29', 'jYYYY-jMM-jDD'); }
در این تصویر روزهای خاکستری، قابل انتخاب نیستند و غیرفعال شدهاند (چون min به 10 مهر و max به 29 مهر تنظیم شدهاست).
4) غیرفعال کردن روزهای قابل انتخاب بر اساس یک منطق سفارشی
<mat-form-field> <input matInput [matDatepicker]="picker4" [matDatepickerFilter]="myFilter" placeholder="Date validation - Datepicker Filter"> <mat-datepicker-toggle matSuffix [for]="picker4"></mat-datepicker-toggle> <mat-datepicker #picker4></mat-datepicker> </mat-form-field>
import * as moment from "jalali-moment"; @Component() export class PersianDatepickerComponent { myFilter = (d: moment.Moment): boolean => { const day: number = d.day(); // Prevent Thursday and Friday from being selected. return day !== 5 && day !== 4; } }
5) کار با رخدادهای تقویم
<mat-form-field> <input matInput [matDatepicker]="picker5" (dateInput)="onInput($event)" (dateChange)="onChange($event)" placeholder="dateInput and dateChange events"> <mat-datepicker-toggle matSuffix [for]="picker5"></mat-datepicker-toggle> <mat-datepicker #picker5></mat-datepicker> </mat-form-field>
import { MatDatepickerInputEvent } from "@angular/material"; import * as moment from "jalali-moment"; @Component() export class PersianDatepickerComponent { onInput(event: MatDatepickerInputEvent<moment.Moment>) { console.log("OnInput: ", event.value); } onChange(event: MatDatepickerInputEvent<moment.Moment>) { const x = moment(event.value).format("jYYYY/jMM/jDD"); console.log("OnChange: ", x); } }
در اینجا، onInput، با ورود دستی اطلاعات به textbox کامپوننت، فعال میشود و onChange، در صورت انتخاب یک تاریخ از تقویم.
کدهای کامل این مثال را از اینجا میتوانید دریافت کنید.