Last active
June 30, 2026 20:30
-
-
Save SippieCup/657cca1da2db92bc6e6c96632bf93962 to your computer and use it in GitHub Desktop.
luxon support for primeng
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* eslint-disable @typescript-eslint/no-explicit-any */ | |
| /* eslint-disable @typescript-eslint/no-empty-function */ | |
| import { Directive, OnInit, inject, input } from '@angular/core'; | |
| import { ControlValueAccessor, NgControl } from '@angular/forms'; | |
| import { DateTime, Settings } from 'luxon'; | |
| @Directive({ | |
| // eslint-disable-next-line angular/directive-selector | |
| selector: '[luxonDate]', // Ensure it only applies to p-datepicker | |
| standalone: true, | |
| }) | |
| export class LuxonDateDirective implements ControlValueAccessor, OnInit { | |
| overrideZone = input<string | undefined>(); // Optional override for timezone | |
| overrideLocale = input<string | undefined>(); // Optional override for locale | |
| private ngControl = inject(NgControl, { optional: true, self: true }); | |
| private onChange: (value: any) => void = () => {}; | |
| private onTouched: () => void = () => {}; | |
| // A reference to the original value accessor from p-datepicker | |
| private originalAccessor: ControlValueAccessor | null = null; | |
| constructor() { | |
| if (this.ngControl) { | |
| // Save the original value accessor and replace it with this directive | |
| this.originalAccessor = this.ngControl.valueAccessor; | |
| this.ngControl.valueAccessor = this; | |
| } | |
| } | |
| ngOnInit(): void { | |
| if (!this.originalAccessor) { | |
| console.warn('LuxonDateDirective: No original accessor found on NgControl.'); | |
| } | |
| } | |
| // Converts JavaScript Date to Luxon DateTime<true> or null | |
| private toLuxon(input: Date | Date[] | null): DateTime<true> | DateTime<true>[] | null { | |
| if (!input) return null; | |
| if (Array.isArray(input)) { | |
| return input | |
| .map((d) => { | |
| const dt = DateTime.fromJSDate(d, { | |
| zone: this.overrideZone() || Settings.defaultZone, | |
| }); | |
| return dt.isValid ? (dt as DateTime<true>) : null; | |
| }) | |
| .filter(Boolean) as DateTime<true>[]; | |
| } else { | |
| const dt = DateTime.fromJSDate(input, { | |
| zone: this.overrideZone() || Settings.defaultZone, | |
| }); | |
| return dt.isValid ? (dt as DateTime<true>) : null; | |
| } | |
| } | |
| // Converts a valid Luxon DateTime<true> to JavaScript Date or null | |
| private toJsDate(input: DateTime<true> | DateTime<true>[] | null): Date | Date[] | null { | |
| if (!input) return null; | |
| if (Array.isArray(input)) { | |
| return input.map((dt) => (dt ? dt.toJSDate() : null)).filter(Boolean) as Date[]; | |
| } else { | |
| return input ? input.toJSDate() : null; | |
| } | |
| } | |
| // Intercept the `writeValue` call and convert Luxon to JS Date | |
| writeValue(value: any): void { | |
| const jsValue = Array.isArray(value) | |
| ? this.toJsDate(value as DateTime<true>[]) | |
| : this.toJsDate(value as DateTime<true>); | |
| if (this.originalAccessor) { | |
| this.originalAccessor.writeValue(jsValue); | |
| } | |
| } | |
| // Intercept the `registerOnChange` call and handle Luxon conversion | |
| registerOnChange(fn: (value: any) => void): void { | |
| this.onChange = (jsValue: Date | Date[] | null) => { | |
| const luxonValue = this.toLuxon(jsValue); | |
| fn(luxonValue); | |
| }; | |
| if (this.originalAccessor) { | |
| this.originalAccessor.registerOnChange((value: any) => { | |
| this.onChange(value); | |
| }); | |
| } | |
| } | |
| // Delegate the `registerOnTouched` to the original accessor | |
| registerOnTouched(fn: () => void): void { | |
| this.onTouched = fn; | |
| if (this.originalAccessor) { | |
| this.originalAccessor.registerOnTouched(fn); | |
| } | |
| } | |
| // Delegate the `setDisabledState` to the original accessor | |
| setDisabledState(isDisabled: boolean): void { | |
| if (this.originalAccessor && this.originalAccessor.setDisabledState) { | |
| this.originalAccessor.setDisabledState(isDisabled); | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment