@anglr/datetime 9.0.2 → 9.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/skills/angular-developer/SKILL.md +130 -0
- package/.claude/skills/angular-developer/references/angular-animations.md +160 -0
- package/.claude/skills/angular-developer/references/angular-aria.md +410 -0
- package/.claude/skills/angular-developer/references/cli.md +86 -0
- package/.claude/skills/angular-developer/references/component-harnesses.md +59 -0
- package/.claude/skills/angular-developer/references/component-styling.md +91 -0
- package/.claude/skills/angular-developer/references/components.md +117 -0
- package/.claude/skills/angular-developer/references/creating-services.md +97 -0
- package/.claude/skills/angular-developer/references/data-resolvers.md +69 -0
- package/.claude/skills/angular-developer/references/define-routes.md +67 -0
- package/.claude/skills/angular-developer/references/defining-providers.md +72 -0
- package/.claude/skills/angular-developer/references/di-fundamentals.md +120 -0
- package/.claude/skills/angular-developer/references/e2e-testing.md +66 -0
- package/.claude/skills/angular-developer/references/effects.md +83 -0
- package/.claude/skills/angular-developer/references/hierarchical-injectors.md +43 -0
- package/.claude/skills/angular-developer/references/host-elements.md +80 -0
- package/.claude/skills/angular-developer/references/injection-context.md +63 -0
- package/.claude/skills/angular-developer/references/inputs.md +101 -0
- package/.claude/skills/angular-developer/references/linked-signal.md +59 -0
- package/.claude/skills/angular-developer/references/loading-strategies.md +61 -0
- package/.claude/skills/angular-developer/references/mcp.md +106 -0
- package/.claude/skills/angular-developer/references/migrations.md +30 -0
- package/.claude/skills/angular-developer/references/navigate-to-routes.md +69 -0
- package/.claude/skills/angular-developer/references/outputs.md +86 -0
- package/.claude/skills/angular-developer/references/reactive-forms.md +122 -0
- package/.claude/skills/angular-developer/references/rendering-strategies.md +44 -0
- package/.claude/skills/angular-developer/references/resource.md +77 -0
- package/.claude/skills/angular-developer/references/route-animations.md +56 -0
- package/.claude/skills/angular-developer/references/route-guards.md +52 -0
- package/.claude/skills/angular-developer/references/router-lifecycle.md +45 -0
- package/.claude/skills/angular-developer/references/router-testing.md +87 -0
- package/.claude/skills/angular-developer/references/show-routes-with-outlets.md +68 -0
- package/.claude/skills/angular-developer/references/signal-forms.md +897 -0
- package/.claude/skills/angular-developer/references/signals-overview.md +94 -0
- package/.claude/skills/angular-developer/references/tailwind-css.md +69 -0
- package/.claude/skills/angular-developer/references/template-driven-forms.md +114 -0
- package/.claude/skills/angular-developer/references/testing-fundamentals.md +66 -0
- package/.github/instructions/typescript/code-conventions.md +8 -0
- package/.github/instructions/typescript/comments.md +41 -0
- package/.github/instructions/typescript/formatting.md +43 -0
- package/.github/instructions/typescript/naming-conventions.md +7 -0
- package/.github/instructions/typescript.instructions.md +26 -0
- package/changelog.md +6 -0
- package/es2022/src/services/dateValueProvider/dateValueProvider.service.js +1 -1
- package/es2022/src/services/dateValueProvider/dateValueProvider.service.js.map +1 -1
- package/package.json +1 -1
- package/readme.md +1453 -4
- package/version.bak +1 -1
package/readme.md
CHANGED
|
@@ -1,11 +1,1460 @@
|
|
|
1
1
|
[](https://badge.fury.io/js/%40anglr%2Fdatetime)
|
|
2
2
|
[](https://ci.appveyor.com/project/kukjevov/ng-datetime)
|
|
3
3
|
|
|
4
|
-
#
|
|
4
|
+
# @anglr/datetime
|
|
5
|
+
|
|
6
|
+
> Angular library for datetime input, manipulation, validation, formatting, and calendar/picker UI components with pluggable date adapters (date-fns, Moment.js, or any other implementing `DateApiObject`).
|
|
5
7
|
|
|
6
8
|
- [API](https://ressurectit.github.io/#/content/api/ng-datetime/datetime)
|
|
7
|
-
- [API
|
|
8
|
-
- [API
|
|
9
|
+
- [API Date FNS](https://ressurectit.github.io/#/content/api/ng-datetime-date-fns/datetime-date-fns)
|
|
10
|
+
- [API Moment](https://ressurectit.github.io/#/content/api/ng-datetime-moment/datetime-moment)
|
|
9
11
|
- [Samples](https://ressurectit.github.io/#/content/datetime#samples)
|
|
10
12
|
|
|
11
|
-
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Table of Contents
|
|
16
|
+
|
|
17
|
+
- [Why Use This Library?](#why-use-this-library)
|
|
18
|
+
- [Installation](#installation)
|
|
19
|
+
- [Architecture Overview](#architecture-overview)
|
|
20
|
+
- [Date Adapters](#date-adapters)
|
|
21
|
+
- [Modules](#modules)
|
|
22
|
+
- [Directives](#directives)
|
|
23
|
+
- [Pipes](#pipes)
|
|
24
|
+
- [Services](#services)
|
|
25
|
+
- [Validators](#validators)
|
|
26
|
+
- [Calendar](#calendar)
|
|
27
|
+
- [Date/Time Picker](#datetime-picker)
|
|
28
|
+
- [Theming & Styles](#theming--styles)
|
|
29
|
+
- [Usage Examples](#usage-examples)
|
|
30
|
+
- [Samples](#samples)
|
|
31
|
+
- [Advanced Usage](#advanced-usage)
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## Why Use This Library?
|
|
36
|
+
|
|
37
|
+
- **Adapter-based architecture** — swap between `date-fns` and `Moment.js` (or your custom implementation) without changing your templates or component code.
|
|
38
|
+
- **Standalone directives** — tree-shakable, composable, use only what you need.
|
|
39
|
+
- **Rich keyboard handling** — arrow key navigation between date parts, increment/decrement with constraints, auto-selection of date segments.
|
|
40
|
+
- **Built-in validation** — min/max/format validators with Angular Reactive and Template-driven forms integration.
|
|
41
|
+
- **Flexible pickers** — configurable day/month/year/time pickers with positioning, CSS classes, and behavioral options.
|
|
42
|
+
- **Calendar component** — full month calendar with event support, custom day templates, and aspect ratio control.
|
|
43
|
+
- **Pipes for display** — format, convert, and compare dates directly in templates.
|
|
44
|
+
- **i18n-ready** — locale support via date-fns locales or Moment locale system.
|
|
45
|
+
- **Relative date parsing** — support for expressions like `+5d`, `-2M`, `+1y`.
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## Installation
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
npm install @anglr/datetime
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Choose your date adapter:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
# date-fns (recommended)
|
|
59
|
+
npm install date-fns
|
|
60
|
+
|
|
61
|
+
# or Moment.js
|
|
62
|
+
npm install moment
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
**Peer dependencies:**
|
|
66
|
+
|
|
67
|
+
- `@angular/core` >= 19.1.0
|
|
68
|
+
- `@angular/forms` >= 19.1.0
|
|
69
|
+
- `@angular/common` >= 19.1.0
|
|
70
|
+
- `@angular/animations` >= 19.1.0
|
|
71
|
+
- `@anglr/common` >= 22.0.0
|
|
72
|
+
- `@jscrpt/common` >= 7.0.0
|
|
73
|
+
- `rxjs` >= 7.5.7
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## Architecture Overview
|
|
78
|
+
|
|
79
|
+
```
|
|
80
|
+
┌─────────────────────────────────────────────────┐
|
|
81
|
+
│ Your Application │
|
|
82
|
+
├──────────────────┬──────────────────────────────┤
|
|
83
|
+
│ Directives │ Pipes / Validators │
|
|
84
|
+
│ (date inputs, │ (dateFormat, isAfter, │
|
|
85
|
+
│ pickers, etc.) │ datetimeMin, etc.) │
|
|
86
|
+
├──────────────────┴──────────────────────────────┤
|
|
87
|
+
│ Core Services │
|
|
88
|
+
│ (DateApi, DatePositionParser, │
|
|
89
|
+
│ DateTimeRelativeParser, DateValueProvider) │
|
|
90
|
+
├─────────────────────────────────────────────────┤
|
|
91
|
+
│ Adapter Layer (DI tokens) │
|
|
92
|
+
│ ┌──────────────────┐ ┌────────────────────┐ │
|
|
93
|
+
│ │ date-fns adapter │ │ Moment.js adapter │ │
|
|
94
|
+
│ │ DateFnsDateApi │ │ MomentDateApi │ │
|
|
95
|
+
│ └──────────────────┘ └────────────────────┘ │
|
|
96
|
+
└─────────────────────────────────────────────────┘
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
The library uses Angular dependency injection tokens (`DATE_API`, `FORMAT_PROVIDER`, `DATE_API_OBJECT_TYPE`) allowing you to plug in any adapter at the application root.
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## Date Adapters
|
|
104
|
+
|
|
105
|
+
### date-fns Adapter
|
|
106
|
+
|
|
107
|
+
Import path: `@anglr/datetime/date-fns`
|
|
108
|
+
|
|
109
|
+
```typescript
|
|
110
|
+
import {DATE_API} from '@anglr/datetime';
|
|
111
|
+
import {DateFnsDateApi, DateFnsLocale, DATE_FNS_DATE_API_OBJECT_TYPE, DATE_FNS_FORMAT_PROVIDER, DATE_FNS_LOCALE} from '@anglr/datetime/date-fns';
|
|
112
|
+
import {sk} from 'date-fns/locale';
|
|
113
|
+
|
|
114
|
+
export const appProviders =
|
|
115
|
+
[
|
|
116
|
+
{
|
|
117
|
+
provide: DATE_API,
|
|
118
|
+
useClass: DateFnsDateApi,
|
|
119
|
+
},
|
|
120
|
+
DATE_FNS_FORMAT_PROVIDER,
|
|
121
|
+
DATE_FNS_DATE_API_OBJECT_TYPE,
|
|
122
|
+
{
|
|
123
|
+
provide: DATE_FNS_LOCALE,
|
|
124
|
+
useValue: <DateFnsLocale>
|
|
125
|
+
{
|
|
126
|
+
locale: sk,
|
|
127
|
+
},
|
|
128
|
+
},
|
|
129
|
+
];
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Default format tokens provided by `DATE_FNS_FORMAT_PROVIDER`:
|
|
133
|
+
|
|
134
|
+
| Token | Format |
|
|
135
|
+
|-------|--------|
|
|
136
|
+
| `date` | `'P'` (locale-aware) |
|
|
137
|
+
| `dateTime` | `'Pp'` |
|
|
138
|
+
| `time` | `'p'` |
|
|
139
|
+
| `year` | `'yyyy'` |
|
|
140
|
+
| `month` | `'MM'` |
|
|
141
|
+
| `day` | `'dd'` |
|
|
142
|
+
| `hour` | `'HH'` |
|
|
143
|
+
| `minute` | `'mm'` |
|
|
144
|
+
| `second` | `'ss'` |
|
|
145
|
+
|
|
146
|
+
### Moment.js Adapter
|
|
147
|
+
|
|
148
|
+
Import path: `@anglr/datetime/moment`
|
|
149
|
+
|
|
150
|
+
```typescript
|
|
151
|
+
import {DATE_API} from '@anglr/datetime';
|
|
152
|
+
import {MomentDateApi, MOMENT_FORMAT_PROVIDER, MOMENT_DATE_API_OBJECT_TYPE} from '@anglr/datetime/moment';
|
|
153
|
+
|
|
154
|
+
export const appProviders =
|
|
155
|
+
[
|
|
156
|
+
{
|
|
157
|
+
provide: DATE_API,
|
|
158
|
+
useClass: MomentDateApi,
|
|
159
|
+
},
|
|
160
|
+
MOMENT_FORMAT_PROVIDER,
|
|
161
|
+
MOMENT_DATE_API_OBJECT_TYPE,
|
|
162
|
+
];
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### Custom Format Provider
|
|
166
|
+
|
|
167
|
+
Override the default format tokens:
|
|
168
|
+
|
|
169
|
+
```typescript
|
|
170
|
+
import {FORMAT_PROVIDER, FormatProvider} from '@anglr/datetime';
|
|
171
|
+
|
|
172
|
+
{
|
|
173
|
+
provide: FORMAT_PROVIDER,
|
|
174
|
+
useFactory: () =>
|
|
175
|
+
{
|
|
176
|
+
return <FormatProvider>{
|
|
177
|
+
date: 'd.M.y',
|
|
178
|
+
dateTime: 'd.M.y HH:mm',
|
|
179
|
+
time: 'HH:mm',
|
|
180
|
+
year: 'yyyy',
|
|
181
|
+
month: 'MM',
|
|
182
|
+
week: 'ww',
|
|
183
|
+
day: 'DD',
|
|
184
|
+
hour: 'HH',
|
|
185
|
+
minute: 'mm',
|
|
186
|
+
second: 'ss',
|
|
187
|
+
dayName: 'dddd',
|
|
188
|
+
dayNameShort: 'dd',
|
|
189
|
+
monthName: 'MMMM',
|
|
190
|
+
monthNameShort: 'MMM',
|
|
191
|
+
};
|
|
192
|
+
},
|
|
193
|
+
}
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
---
|
|
197
|
+
|
|
198
|
+
## Modules
|
|
199
|
+
|
|
200
|
+
| Module | Description |
|
|
201
|
+
|--------|-------------|
|
|
202
|
+
| `DateTimeModule` | Core directives: `DateTimeDirective`, `DateTimeInputDirective`, `DateTimeControlValueAccessorDirective`, validators |
|
|
203
|
+
| `DateTimePickerModule` | `DateTimePickerComponent`, `DateTimePickerDirective` |
|
|
204
|
+
| `MonthCalendarModule` | `MonthCalendarComponent`, `CalendarDayTemplateDirective` |
|
|
205
|
+
| `DatePipesModule` | `dateFormat`, `dateConvert`, `isAfter`, `isBefore` pipes |
|
|
206
|
+
|
|
207
|
+
---
|
|
208
|
+
|
|
209
|
+
## Directives
|
|
210
|
+
|
|
211
|
+
### Composite (ready-to-use) Directives
|
|
212
|
+
|
|
213
|
+
These combine multiple internal directives for common use cases:
|
|
214
|
+
|
|
215
|
+
| Directive | Selector | Description |
|
|
216
|
+
|-----------|----------|-------------|
|
|
217
|
+
| `DatePickerInputDirective` | `input[dateTime][datePickerInput]` | Full date picker with advanced keyboard handler |
|
|
218
|
+
| `DateTimePickerInputDirective` | `input[dateTime][dateTimePickerInput]` | Full date + time picker with advanced keyboard handler |
|
|
219
|
+
| `SimpleDatePickerInputDirective` | `input[dateTime][simpleDatePickerInput]` | Date picker with simple keyboard handler |
|
|
220
|
+
| `SimpleDateTimePickerInputDirective` | `input[dateTime][simpleDateTimePickerInput]` | Date + time picker with simple keyboard handler |
|
|
221
|
+
| `ButtonDateTimeInputDirective` | `button[dateTime][dateTimeInput]` | Date/time input rendered as button/link |
|
|
222
|
+
|
|
223
|
+
### Behavior Directives
|
|
224
|
+
|
|
225
|
+
| Directive | Selector | Description |
|
|
226
|
+
|-----------|----------|-------------|
|
|
227
|
+
| `WithNowDirective` | `[dateTime][withNow]` | Sets value to current date/time on focus (if empty) |
|
|
228
|
+
| `WithTodayDirective` | `[dateTime][withToday]` | Sets value to start of today on focus (if empty) |
|
|
229
|
+
| `WithTimeDirective` | `[dateTime][withPicker][withTime]` | Adds time picker component and switches format to `'dateTime'` |
|
|
230
|
+
|
|
231
|
+
### Core Directives
|
|
232
|
+
|
|
233
|
+
| Directive | Selector | Description |
|
|
234
|
+
|-----------|----------|-------------|
|
|
235
|
+
| `DateTimeDirective` | `[dateTime]` | Shared data holder (format, restrictions, validation config) |
|
|
236
|
+
| `DateTimeInputDirective` | `input[dateTime][dateTimeInput]` | Text input with value parsing |
|
|
237
|
+
| `DateTimeInputHandlerDirective` | `[dateTime][withHandler]` | Advanced keyboard navigation (arrow keys navigate date parts) |
|
|
238
|
+
| `SimpleDateTimeInputHandlerDirective` | `[dateTime][withSimpleHandler]` | Simple keyboard (arrows: ±day/±week, Ctrl+Space: open picker) |
|
|
239
|
+
| `DateTimePickerDirective` | `[dateTime][withPicker]` | Controls picker component visibility and positioning |
|
|
240
|
+
| `DateTimeControlValueAccessorDirective` | `[dateTime][valueFormat]` | Angular ControlValueAccessor integration |
|
|
241
|
+
| `DateTimeValidatorDirective` | — | Validates date is valid format |
|
|
242
|
+
| `DateTimeMinValidatorDirective` | — | Validates date >= min |
|
|
243
|
+
| `DateTimeMaxValidatorDirective` | — | Validates date <= max |
|
|
244
|
+
|
|
245
|
+
### Keyboard Handlers
|
|
246
|
+
|
|
247
|
+
**`DateTimeInputHandlerDirective` (Advanced):**
|
|
248
|
+
- Left/Right arrows: Navigate between date segments (year → month → day → hour → minute)
|
|
249
|
+
- Up/Down arrows: Increment/decrement current segment with min/max constraints
|
|
250
|
+
- Typed characters: Replace selected segment with validation
|
|
251
|
+
- Click/select: Auto-select current date part
|
|
252
|
+
|
|
253
|
+
**`SimpleDateTimeInputHandlerDirective` (Simple):**
|
|
254
|
+
- Left/Right arrows: ±1 day
|
|
255
|
+
- Up/Down arrows: ±1 week
|
|
256
|
+
- Escape: Close picker
|
|
257
|
+
- Ctrl+Space: Open picker
|
|
258
|
+
|
|
259
|
+
---
|
|
260
|
+
|
|
261
|
+
## Pipes
|
|
262
|
+
|
|
263
|
+
| Pipe | Syntax | Description |
|
|
264
|
+
|------|--------|-------------|
|
|
265
|
+
| `dateFormat` | `{{ value \| dateFormat }}` | Format with default `'date'` format |
|
|
266
|
+
| `dateFormat` | `{{ value \| dateFormat: 'dateTime' }}` | Format with FormatProvider key |
|
|
267
|
+
| `dateFormat` | `{{ value \| dateFormat: 'yyyy-MM-dd' : true }}` | Format with custom format string |
|
|
268
|
+
| `dateConvert` | `{{ value \| dateConvert }}` | Convert to DateApiObject wrapper |
|
|
269
|
+
| `dateConvert` | `{{ value \| dateConvert: 'yyyy-MM-dd' }}` | Convert with parse format |
|
|
270
|
+
| `isAfter` | `{{ date1 \| isAfter: date2 }}` | Test if date1 is after date2 |
|
|
271
|
+
| `isBefore` | `{{ date1 \| isBefore: date2 }}` | Test if date1 is before date2 |
|
|
272
|
+
|
|
273
|
+
---
|
|
274
|
+
|
|
275
|
+
## Services
|
|
276
|
+
|
|
277
|
+
### DateApi\<TDate\>
|
|
278
|
+
|
|
279
|
+
Core abstraction for date manipulation. Injected via `DATE_API` token.
|
|
280
|
+
|
|
281
|
+
```typescript
|
|
282
|
+
import {Component, inject} from '@angular/core';
|
|
283
|
+
import {DATE_API, DateApi} from '@anglr/datetime';
|
|
284
|
+
|
|
285
|
+
@Component(
|
|
286
|
+
{
|
|
287
|
+
/* ... */
|
|
288
|
+
})
|
|
289
|
+
export class ExampleComponent
|
|
290
|
+
{
|
|
291
|
+
private readonly dateApi: DateApi<Date> = inject<DateApi<Date>>(DATE_API);
|
|
292
|
+
|
|
293
|
+
example(): void
|
|
294
|
+
{
|
|
295
|
+
// Create date object
|
|
296
|
+
const today = this.dateApi.now();
|
|
297
|
+
|
|
298
|
+
// Parse value
|
|
299
|
+
const date = this.dateApi.getValue('2024-01-15', 'yyyy-MM-dd');
|
|
300
|
+
|
|
301
|
+
// Fluent API
|
|
302
|
+
const formatted = this.dateApi.now()
|
|
303
|
+
.addDays(5)
|
|
304
|
+
.startOfDay()
|
|
305
|
+
.format('yyyy-MM-dd');
|
|
306
|
+
|
|
307
|
+
// Comparisons
|
|
308
|
+
const isAfter = date.isAfter(today.value);
|
|
309
|
+
const isSame = date.isSameMonth(today.value);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
### DateApiObject\<TDate\> (Fluent Wrapper)
|
|
315
|
+
|
|
316
|
+
Wraps a date value with chainable methods:
|
|
317
|
+
|
|
318
|
+
```typescript
|
|
319
|
+
const result = dateApi.getValue('2024-03-15', 'yyyy-MM-dd')
|
|
320
|
+
.startOfMonth() // → 2024-03-01
|
|
321
|
+
.addMonths(2) // → 2024-05-01
|
|
322
|
+
.endOfMonth() // → 2024-05-31
|
|
323
|
+
.format('d.M.yyyy'); // → "31.5.2024"
|
|
324
|
+
|
|
325
|
+
// Getters/Setters
|
|
326
|
+
const year = obj.year(); // get: 2024
|
|
327
|
+
obj.year(2025); // set: 2025
|
|
328
|
+
obj.month(0); // January (0-based)
|
|
329
|
+
obj.dayOfMonth(15);
|
|
330
|
+
|
|
331
|
+
// Period helpers
|
|
332
|
+
obj.startOfDecade();
|
|
333
|
+
obj.endOfYear();
|
|
334
|
+
obj.startOfWeek();
|
|
335
|
+
|
|
336
|
+
// Clone and reset
|
|
337
|
+
const copy = obj.clone();
|
|
338
|
+
obj.resetOriginal(); // revert to initial value
|
|
339
|
+
obj.updateOriginal(); // lock current as new original
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
### DatePositionParserService
|
|
343
|
+
|
|
344
|
+
Parses cursor position within a date string format:
|
|
345
|
+
|
|
346
|
+
```typescript
|
|
347
|
+
import {Component, inject} from '@angular/core';
|
|
348
|
+
import {DatePositionParserService} from '@anglr/datetime';
|
|
349
|
+
|
|
350
|
+
@Component(
|
|
351
|
+
{
|
|
352
|
+
/* ... */
|
|
353
|
+
})
|
|
354
|
+
export class ExampleComponent
|
|
355
|
+
{
|
|
356
|
+
private readonly positionParser: DatePositionParserService = inject(DatePositionParserService);
|
|
357
|
+
|
|
358
|
+
example(): void
|
|
359
|
+
{
|
|
360
|
+
const parser = this.positionParser.createParser('dd.MM.yyyy');
|
|
361
|
+
const result = parser.parse('15.03.2024', 4);
|
|
362
|
+
// result: { positionFrom: 3, positionTo: 5, part: 'month' }
|
|
363
|
+
|
|
364
|
+
parser.next('15.03.2024', 1);
|
|
365
|
+
// moves cursor to month segment
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
### DateTimeRelativeParser\<TDate\>
|
|
371
|
+
|
|
372
|
+
Parses relative date expressions:
|
|
373
|
+
|
|
374
|
+
```typescript
|
|
375
|
+
import {Component, inject} from '@angular/core';
|
|
376
|
+
import {DateTimeRelativeParser} from '@anglr/datetime';
|
|
377
|
+
|
|
378
|
+
@Component(
|
|
379
|
+
{
|
|
380
|
+
/* ... */
|
|
381
|
+
})
|
|
382
|
+
export class ExampleComponent
|
|
383
|
+
{
|
|
384
|
+
private readonly relativeParser: DateTimeRelativeParser = inject(DateTimeRelativeParser);
|
|
385
|
+
|
|
386
|
+
example(): void
|
|
387
|
+
{
|
|
388
|
+
// Syntax: [+-]\d+[yMwdhm]
|
|
389
|
+
const result1 = this.relativeParser.parse('+5d'); // today + 5 days
|
|
390
|
+
const result2 = this.relativeParser.parse('-2M'); // today - 2 months
|
|
391
|
+
const result3 = this.relativeParser.parse('+1y'); // today + 1 year
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
Supported suffixes: `y` (years), `M` (months), `w` (weeks), `d` (days), `h`/`H` (hours), `m` (minutes).
|
|
397
|
+
|
|
398
|
+
### DateValueProvider\<TDate\>
|
|
399
|
+
|
|
400
|
+
Converts single date values to date ranges based on format granularity:
|
|
401
|
+
|
|
402
|
+
```typescript
|
|
403
|
+
import {Component, inject} from '@angular/core';
|
|
404
|
+
import {DateValueProvider} from '@anglr/datetime';
|
|
405
|
+
|
|
406
|
+
@Component(
|
|
407
|
+
{
|
|
408
|
+
/* ... */
|
|
409
|
+
})
|
|
410
|
+
export class ExampleComponent
|
|
411
|
+
{
|
|
412
|
+
private readonly valueProvider: DateValueProvider = inject(DateValueProvider);
|
|
413
|
+
|
|
414
|
+
example(dateObj: unknown): void
|
|
415
|
+
{
|
|
416
|
+
// For day format: returns startOfDay → endOfDay
|
|
417
|
+
const range = this.valueProvider.getValue(dateObj, 'date');
|
|
418
|
+
// range.from → 2024-03-15 00:00:00
|
|
419
|
+
// range.to → 2024-03-15 23:59:59
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
---
|
|
425
|
+
|
|
426
|
+
## Validators
|
|
427
|
+
|
|
428
|
+
### Template-Driven Forms
|
|
429
|
+
|
|
430
|
+
```html
|
|
431
|
+
<input dateTime simpleDatePickerInput
|
|
432
|
+
[minDateTime]="minDate"
|
|
433
|
+
[maxDateTime]="maxDate">
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
### Reactive Forms (Programmatic)
|
|
437
|
+
|
|
438
|
+
```typescript
|
|
439
|
+
import {Component, inject} from '@angular/core';
|
|
440
|
+
import {FormControl} from '@angular/forms';
|
|
441
|
+
import {DATE_API, DateApi, datetimeValidator, datetimeMinValidator, datetimeMaxValidator, DateTimeValueFormat} from '@anglr/datetime';
|
|
442
|
+
|
|
443
|
+
@Component(
|
|
444
|
+
{
|
|
445
|
+
/* ... */
|
|
446
|
+
})
|
|
447
|
+
export class ValidatorExampleComponent
|
|
448
|
+
{
|
|
449
|
+
private readonly dateApi: DateApi<Date> = inject<DateApi<Date>>(DATE_API);
|
|
450
|
+
|
|
451
|
+
public readonly dateControl: FormControl = new FormControl('2024-01-15', [
|
|
452
|
+
datetimeValidator(this.dateApi, DateTimeValueFormat.FormattedString, 'yyyy-MM-dd'),
|
|
453
|
+
datetimeMinValidator(this.dateApi, '2024-01-01', DateTimeValueFormat.FormattedString, 'yyyy-MM-dd'),
|
|
454
|
+
datetimeMaxValidator(this.dateApi, '2024-12-31', DateTimeValueFormat.FormattedString, 'yyyy-MM-dd'),
|
|
455
|
+
]);
|
|
456
|
+
}
|
|
457
|
+
```
|
|
458
|
+
|
|
459
|
+
### Model-Based Validation (Decorator)
|
|
460
|
+
|
|
461
|
+
```typescript
|
|
462
|
+
import {DateTime, DateTimeValueFormat} from '@anglr/datetime';
|
|
463
|
+
|
|
464
|
+
class MyModel
|
|
465
|
+
{
|
|
466
|
+
@DateTime()
|
|
467
|
+
public dateField: string;
|
|
468
|
+
|
|
469
|
+
@DateTime(DateTimeValueFormat.DataString, 'yyyy-MM-dd', 'yyyy-MM-dd')
|
|
470
|
+
public startDate: string;
|
|
471
|
+
}
|
|
472
|
+
```
|
|
473
|
+
|
|
474
|
+
### Value Format Options
|
|
475
|
+
|
|
476
|
+
| Format | Description |
|
|
477
|
+
|--------|-------------|
|
|
478
|
+
| `DateTimeValueFormat.DateInstance` | Native JS Date object |
|
|
479
|
+
| `DateTimeValueFormat.UnixTimestamp` | Seconds since epoch |
|
|
480
|
+
| `DateTimeValueFormat.Timestamp` | Milliseconds since epoch |
|
|
481
|
+
| `DateTimeValueFormat.FormattedString` | Display format string |
|
|
482
|
+
| `DateTimeValueFormat.DataString` | Data-specific format string |
|
|
483
|
+
| `DateTimeValueFormat.RangeOfDateInstances` | Period with `from` / `to` |
|
|
484
|
+
|
|
485
|
+
---
|
|
486
|
+
|
|
487
|
+
## Calendar
|
|
488
|
+
|
|
489
|
+
The `MonthCalendarComponent` displays a full month calendar with event support.
|
|
490
|
+
|
|
491
|
+
```typescript
|
|
492
|
+
import {ChangeDetectionStrategy, Component} from '@angular/core';
|
|
493
|
+
import {CalendarDayAspectRatio, EventData, MonthCalendarDayFormat, MonthCalendarModule} from '@anglr/datetime';
|
|
494
|
+
|
|
495
|
+
@Component(
|
|
496
|
+
{
|
|
497
|
+
template: `
|
|
498
|
+
<month-calendar [display]="currentMonth"
|
|
499
|
+
[events]="events"
|
|
500
|
+
[showWeekNumber]="true"
|
|
501
|
+
[dayAspectRatio]="CalendarDayAspectRatio.FourToThree"
|
|
502
|
+
[weekDayName]="MonthCalendarDayFormat.Short">
|
|
503
|
+
<ng-template calendarDayTemplate let-day>
|
|
504
|
+
<div class="day-number">{{ day.day }}</div>
|
|
505
|
+
@for (event of day.events; track event) {
|
|
506
|
+
<div class="event" [class.all-day]="event.allDay">
|
|
507
|
+
{{ $any(event.data).title }}
|
|
508
|
+
</div>
|
|
509
|
+
}
|
|
510
|
+
</ng-template>
|
|
511
|
+
</month-calendar>
|
|
512
|
+
`,
|
|
513
|
+
imports:
|
|
514
|
+
[
|
|
515
|
+
MonthCalendarModule,
|
|
516
|
+
],
|
|
517
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
518
|
+
})
|
|
519
|
+
export class CalendarPageComponent
|
|
520
|
+
{
|
|
521
|
+
protected readonly CalendarDayAspectRatio: typeof CalendarDayAspectRatio = CalendarDayAspectRatio;
|
|
522
|
+
protected readonly MonthCalendarDayFormat: typeof MonthCalendarDayFormat = MonthCalendarDayFormat;
|
|
523
|
+
|
|
524
|
+
public currentMonth: Date = new Date();
|
|
525
|
+
public events: EventData<Date, MyEvent>[] =
|
|
526
|
+
[
|
|
527
|
+
{data: {title: 'Meeting'}, dateFrom: new Date(2024, 2, 15), dateTo: new Date(2024, 2, 15)},
|
|
528
|
+
{data: {title: 'Conference'}, dateFrom: new Date(2024, 2, 20), dateTo: new Date(2024, 2, 22)},
|
|
529
|
+
];
|
|
530
|
+
}
|
|
531
|
+
```
|
|
532
|
+
|
|
533
|
+
### Calendar Day Aspect Ratios
|
|
534
|
+
|
|
535
|
+
| Enum | Ratio | Value |
|
|
536
|
+
|------|-------|-------|
|
|
537
|
+
| `OneToOne` | 1:1 | 100 |
|
|
538
|
+
| `ThreeToTwo` | 3:2 | 66.66 |
|
|
539
|
+
| `FourToThree` | 4:3 | 75 |
|
|
540
|
+
| `SixteenToTen` | 16:10 | 62.5 |
|
|
541
|
+
| `SixteenToNine` | 16:9 | 56.25 |
|
|
542
|
+
|
|
543
|
+
---
|
|
544
|
+
|
|
545
|
+
## Date/Time Picker
|
|
546
|
+
|
|
547
|
+
### Picker Components
|
|
548
|
+
|
|
549
|
+
| Component | Description |
|
|
550
|
+
|-----------|-------------|
|
|
551
|
+
| `DayPickerComponent` | Day grid for selecting a date within a month |
|
|
552
|
+
| `MonthPickerComponent` | Month grid for selecting a month within a year |
|
|
553
|
+
| `YearPickerComponent` | Year grid for selecting a year within a decade |
|
|
554
|
+
| `RollerTimePickerComponent` | Scrollable time picker (hours, minutes) |
|
|
555
|
+
|
|
556
|
+
### Picker Options
|
|
557
|
+
|
|
558
|
+
```typescript
|
|
559
|
+
import {DateTimePickerDirective, DateTimePickerDirectiveOptions} from '@anglr/datetime';
|
|
560
|
+
|
|
561
|
+
// In template:
|
|
562
|
+
// <input dateTime simpleDatePickerInput [withPickerOptions]="pickerOptions">
|
|
563
|
+
|
|
564
|
+
pickerOptions: DateTimePickerDirectiveOptions =
|
|
565
|
+
{
|
|
566
|
+
closeOnValueSelect: true,
|
|
567
|
+
closeOnBlur: true,
|
|
568
|
+
showOnFocus: true,
|
|
569
|
+
disabled: false,
|
|
570
|
+
absolute: true,
|
|
571
|
+
pickerCssClass: 'my-custom-picker',
|
|
572
|
+
};
|
|
573
|
+
```
|
|
574
|
+
|
|
575
|
+
### Custom Picker Periods
|
|
576
|
+
|
|
577
|
+
```typescript
|
|
578
|
+
import {Directive} from '@angular/core';
|
|
579
|
+
import {DateTimeDirective, DateTimePickerDirective, DateTimeValueFormat, MonthPickerComponent, YearPickerComponent} from '@anglr/datetime';
|
|
580
|
+
|
|
581
|
+
@Directive(
|
|
582
|
+
{
|
|
583
|
+
/* ... */
|
|
584
|
+
})
|
|
585
|
+
export class CustomPickerDirective<TDate = unknown>
|
|
586
|
+
{
|
|
587
|
+
constructor(picker: DateTimePickerDirective<TDate>,
|
|
588
|
+
dateTime: DateTimeDirective<TDate>)
|
|
589
|
+
{
|
|
590
|
+
picker.pickerOptions =
|
|
591
|
+
{
|
|
592
|
+
defaultPeriod: 'month',
|
|
593
|
+
periodsDefinition:
|
|
594
|
+
{
|
|
595
|
+
'month': MonthPickerComponent,
|
|
596
|
+
'year': YearPickerComponent,
|
|
597
|
+
},
|
|
598
|
+
};
|
|
599
|
+
dateTime.customFormat = 'yyyy-MM';
|
|
600
|
+
dateTime.valueFormat = DateTimeValueFormat.FormattedString;
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
```
|
|
604
|
+
|
|
605
|
+
---
|
|
606
|
+
|
|
607
|
+
## Theming & Styles
|
|
608
|
+
|
|
609
|
+
Import styles via SCSS:
|
|
610
|
+
|
|
611
|
+
```scss
|
|
612
|
+
// All styles
|
|
613
|
+
@use '@anglr/datetime/styles';
|
|
614
|
+
|
|
615
|
+
// Individual themes
|
|
616
|
+
@use '@anglr/datetime/styles/themes/light';
|
|
617
|
+
@use '@anglr/datetime/styles/themes/dark';
|
|
618
|
+
```
|
|
619
|
+
|
|
620
|
+
Available themes: `light`, `dark`.
|
|
621
|
+
|
|
622
|
+
SCSS architecture:
|
|
623
|
+
- `styles/core/_mixins.scss` — Reusable mixins
|
|
624
|
+
- `styles/core/_theme.scss` — Theme variable definitions
|
|
625
|
+
- `styles/core/_functions.scss` — SCSS helper functions
|
|
626
|
+
- `styles/components/_date-time-picker.scss` — Picker component styles
|
|
627
|
+
- `styles/components/_month-calendar.scss` — Calendar component styles
|
|
628
|
+
|
|
629
|
+
---
|
|
630
|
+
|
|
631
|
+
## Usage Examples
|
|
632
|
+
|
|
633
|
+
### Basic Date Picker Input
|
|
634
|
+
|
|
635
|
+
```typescript
|
|
636
|
+
import {ChangeDetectionStrategy, Component} from '@angular/core';
|
|
637
|
+
import {FormControl, ReactiveFormsModule} from '@angular/forms';
|
|
638
|
+
import {DateTimeModule, WithTodayDirective, SimpleDatePickerInputDirective} from '@anglr/datetime';
|
|
639
|
+
|
|
640
|
+
@Component(
|
|
641
|
+
{
|
|
642
|
+
selector: 'my-form',
|
|
643
|
+
template: `
|
|
644
|
+
<input dateTime simpleDatePickerInput withToday
|
|
645
|
+
class="form-control"
|
|
646
|
+
[formControl]="dateControl">
|
|
647
|
+
`,
|
|
648
|
+
imports:
|
|
649
|
+
[
|
|
650
|
+
DateTimeModule,
|
|
651
|
+
WithTodayDirective,
|
|
652
|
+
ReactiveFormsModule,
|
|
653
|
+
SimpleDatePickerInputDirective,
|
|
654
|
+
],
|
|
655
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
656
|
+
})
|
|
657
|
+
export class MyFormComponent
|
|
658
|
+
{
|
|
659
|
+
public readonly dateControl: FormControl = new FormControl('');
|
|
660
|
+
}
|
|
661
|
+
```
|
|
662
|
+
|
|
663
|
+
### Date + Time Picker
|
|
664
|
+
|
|
665
|
+
```typescript
|
|
666
|
+
import {ChangeDetectionStrategy, Component} from '@angular/core';
|
|
667
|
+
import {FormControl, ReactiveFormsModule} from '@angular/forms';
|
|
668
|
+
import {DateTimeModule, WithNowDirective, SimpleDateTimePickerInputDirective} from '@anglr/datetime';
|
|
669
|
+
|
|
670
|
+
@Component(
|
|
671
|
+
{
|
|
672
|
+
template: `
|
|
673
|
+
<input dateTime simpleDateTimePickerInput withNow
|
|
674
|
+
class="form-control"
|
|
675
|
+
[formControl]="dateTimeControl">
|
|
676
|
+
`,
|
|
677
|
+
imports:
|
|
678
|
+
[
|
|
679
|
+
DateTimeModule,
|
|
680
|
+
WithNowDirective,
|
|
681
|
+
ReactiveFormsModule,
|
|
682
|
+
SimpleDateTimePickerInputDirective,
|
|
683
|
+
],
|
|
684
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
685
|
+
})
|
|
686
|
+
export class DateTimeFormComponent
|
|
687
|
+
{
|
|
688
|
+
public readonly dateTimeControl: FormControl = new FormControl('');
|
|
689
|
+
}
|
|
690
|
+
```
|
|
691
|
+
|
|
692
|
+
### Advanced Keyboard-Navigable Date Input
|
|
693
|
+
|
|
694
|
+
```typescript
|
|
695
|
+
import {ChangeDetectionStrategy, Component} from '@angular/core';
|
|
696
|
+
import {FormControl, ReactiveFormsModule} from '@angular/forms';
|
|
697
|
+
import {DateTimeModule, DateTimePickerModule, DatePickerInputDirective} from '@anglr/datetime';
|
|
698
|
+
|
|
699
|
+
@Component(
|
|
700
|
+
{
|
|
701
|
+
template: `
|
|
702
|
+
<input dateTime datePickerInput
|
|
703
|
+
class="form-control"
|
|
704
|
+
[formControl]="dateControl"
|
|
705
|
+
[minDateTime]="minDate"
|
|
706
|
+
[maxDateTime]="maxDate">
|
|
707
|
+
`,
|
|
708
|
+
imports:
|
|
709
|
+
[
|
|
710
|
+
DateTimeModule,
|
|
711
|
+
ReactiveFormsModule,
|
|
712
|
+
DateTimePickerModule,
|
|
713
|
+
DatePickerInputDirective,
|
|
714
|
+
],
|
|
715
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
716
|
+
})
|
|
717
|
+
export class AdvancedDateComponent
|
|
718
|
+
{
|
|
719
|
+
public readonly dateControl: FormControl = new FormControl('');
|
|
720
|
+
public minDate: string = '2024-01-01';
|
|
721
|
+
public maxDate: string = '2024-12-31';
|
|
722
|
+
}
|
|
723
|
+
```
|
|
724
|
+
|
|
725
|
+
### Display Dates with Pipes
|
|
726
|
+
|
|
727
|
+
```typescript
|
|
728
|
+
import {ChangeDetectionStrategy, Component} from '@angular/core';
|
|
729
|
+
import {DatePipesModule} from '@anglr/datetime';
|
|
730
|
+
|
|
731
|
+
@Component(
|
|
732
|
+
{
|
|
733
|
+
template: `
|
|
734
|
+
<!-- Default date format -->
|
|
735
|
+
<span>{{ createdAt | dateFormat }}</span>
|
|
736
|
+
|
|
737
|
+
<!-- Date + time -->
|
|
738
|
+
<span>{{ updatedAt | dateFormat: 'dateTime' }}</span>
|
|
739
|
+
|
|
740
|
+
<!-- Custom format -->
|
|
741
|
+
<span>{{ birthday | dateFormat: 'dd. MMMM yyyy' : true }}</span>
|
|
742
|
+
|
|
743
|
+
<!-- Comparison -->
|
|
744
|
+
@if (endDate | isBefore: today) {
|
|
745
|
+
<span class="expired">Expired</span>
|
|
746
|
+
}
|
|
747
|
+
`,
|
|
748
|
+
imports:
|
|
749
|
+
[
|
|
750
|
+
DatePipesModule,
|
|
751
|
+
],
|
|
752
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
753
|
+
})
|
|
754
|
+
export class DisplayComponent
|
|
755
|
+
{
|
|
756
|
+
public createdAt: string = '2024-03-15T10:30:00Z';
|
|
757
|
+
public updatedAt: Date = new Date();
|
|
758
|
+
public birthday: Date = new Date(1990, 5, 15);
|
|
759
|
+
public endDate: Date = new Date(2024, 0, 1);
|
|
760
|
+
public today: Date = new Date();
|
|
761
|
+
}
|
|
762
|
+
```
|
|
763
|
+
|
|
764
|
+
### Creating a Custom Picker Directive (hostDirectives pattern)
|
|
765
|
+
|
|
766
|
+
```typescript
|
|
767
|
+
import {Directive} from '@angular/core';
|
|
768
|
+
import {
|
|
769
|
+
DateTimeDirective,
|
|
770
|
+
DateTimeValueFormat,
|
|
771
|
+
DateTimeInputDirective,
|
|
772
|
+
DateTimePickerDirective,
|
|
773
|
+
SimpleDateTimeInputHandlerDirective,
|
|
774
|
+
} from '@anglr/datetime';
|
|
775
|
+
|
|
776
|
+
@Directive(
|
|
777
|
+
{
|
|
778
|
+
selector: 'input[dateTime][dayPicker]',
|
|
779
|
+
hostDirectives:
|
|
780
|
+
[
|
|
781
|
+
DateTimeInputDirective,
|
|
782
|
+
DateTimePickerDirective,
|
|
783
|
+
SimpleDateTimeInputHandlerDirective,
|
|
784
|
+
{
|
|
785
|
+
directive: DateTimeDirective,
|
|
786
|
+
inputs: ['minDateTime', 'maxDateTime', 'valueFormat', 'format', 'customFormat', 'dataFormat'],
|
|
787
|
+
},
|
|
788
|
+
],
|
|
789
|
+
})
|
|
790
|
+
export class DayPickerDirective<TDate = unknown>
|
|
791
|
+
{
|
|
792
|
+
constructor(dateTime: DateTimeDirective<TDate>)
|
|
793
|
+
{
|
|
794
|
+
dateTime.valueFormat = DateTimeValueFormat.DataString;
|
|
795
|
+
dateTime.dataFormat = 'yyyy-MM-dd';
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
```
|
|
799
|
+
|
|
800
|
+
Usage in template:
|
|
801
|
+
|
|
802
|
+
```html
|
|
803
|
+
<input dateTime dayPicker class="form-control" [formControl]="myControl">
|
|
804
|
+
```
|
|
805
|
+
|
|
806
|
+
### Month-Only Picker Directive
|
|
807
|
+
|
|
808
|
+
```typescript
|
|
809
|
+
import {Directive} from '@angular/core';
|
|
810
|
+
import {
|
|
811
|
+
DateTimeDirective,
|
|
812
|
+
DateTimeValueFormat,
|
|
813
|
+
MonthPickerComponent,
|
|
814
|
+
YearPickerComponent,
|
|
815
|
+
DateTimeInputDirective,
|
|
816
|
+
DateTimePickerDirective,
|
|
817
|
+
DateTimeInputHandlerDirective,
|
|
818
|
+
} from '@anglr/datetime';
|
|
819
|
+
|
|
820
|
+
@Directive(
|
|
821
|
+
{
|
|
822
|
+
selector: 'input[dateTime][monthPicker]',
|
|
823
|
+
hostDirectives:
|
|
824
|
+
[
|
|
825
|
+
DateTimeInputDirective,
|
|
826
|
+
DateTimePickerDirective,
|
|
827
|
+
DateTimeInputHandlerDirective,
|
|
828
|
+
{
|
|
829
|
+
directive: DateTimeDirective,
|
|
830
|
+
inputs: ['minDateTime', 'maxDateTime'],
|
|
831
|
+
},
|
|
832
|
+
],
|
|
833
|
+
})
|
|
834
|
+
export class MonthPickerDirective<TDate = unknown>
|
|
835
|
+
{
|
|
836
|
+
constructor(picker: DateTimePickerDirective<TDate>,
|
|
837
|
+
dateTime: DateTimeDirective<TDate>)
|
|
838
|
+
{
|
|
839
|
+
picker.pickerOptions =
|
|
840
|
+
{
|
|
841
|
+
defaultPeriod: 'month',
|
|
842
|
+
periodsDefinition:
|
|
843
|
+
{
|
|
844
|
+
'month': MonthPickerComponent,
|
|
845
|
+
'year': YearPickerComponent,
|
|
846
|
+
},
|
|
847
|
+
};
|
|
848
|
+
dateTime.customFormat = 'yyyy-MM';
|
|
849
|
+
dateTime.valueFormat = DateTimeValueFormat.FormattedString;
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
```
|
|
853
|
+
|
|
854
|
+
### Day + Time Picker with DataString Output
|
|
855
|
+
|
|
856
|
+
```typescript
|
|
857
|
+
import {Directive} from '@angular/core';
|
|
858
|
+
import {
|
|
859
|
+
DateTimeDirective,
|
|
860
|
+
DateTimeValueFormat,
|
|
861
|
+
WithTimeDirective,
|
|
862
|
+
DateTimeInputDirective,
|
|
863
|
+
DateTimePickerDirective,
|
|
864
|
+
SimpleDateTimeInputHandlerDirective,
|
|
865
|
+
} from '@anglr/datetime';
|
|
866
|
+
|
|
867
|
+
@Directive(
|
|
868
|
+
{
|
|
869
|
+
selector: 'input[dateTime][dayTimePicker]',
|
|
870
|
+
hostDirectives:
|
|
871
|
+
[
|
|
872
|
+
WithTimeDirective,
|
|
873
|
+
DateTimeInputDirective,
|
|
874
|
+
DateTimePickerDirective,
|
|
875
|
+
SimpleDateTimeInputHandlerDirective,
|
|
876
|
+
{
|
|
877
|
+
directive: DateTimeDirective,
|
|
878
|
+
inputs: ['minDateTime', 'maxDateTime', 'valueFormat', 'format', 'customFormat', 'dataFormat'],
|
|
879
|
+
},
|
|
880
|
+
],
|
|
881
|
+
})
|
|
882
|
+
export class DayTimePickerDirective<TDate = unknown>
|
|
883
|
+
{
|
|
884
|
+
constructor(dateTime: DateTimeDirective<TDate>)
|
|
885
|
+
{
|
|
886
|
+
dateTime.valueFormat = DateTimeValueFormat.DataString;
|
|
887
|
+
dateTime.dataFormat = "yyyy-MM-dd'T'HH:mm:ss";
|
|
888
|
+
}
|
|
889
|
+
}
|
|
890
|
+
```
|
|
891
|
+
|
|
892
|
+
### Extending DateApiObject with Custom Methods
|
|
893
|
+
|
|
894
|
+
```typescript
|
|
895
|
+
import {DateApiObject} from '@anglr/datetime';
|
|
896
|
+
import {DateFnsDateApiObject} from '@anglr/datetime/date-fns';
|
|
897
|
+
import {differenceInMonths, differenceInYears, differenceInSeconds} from 'date-fns';
|
|
898
|
+
|
|
899
|
+
export class DateApiExtension extends DateFnsDateApiObject
|
|
900
|
+
{
|
|
901
|
+
public override clone(): DateApiObject<Date>
|
|
902
|
+
{
|
|
903
|
+
return new DateApiExtension(new Date(this._value), null, this._localeSvc);
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
public override cloneOriginal(): DateApiObject<Date>
|
|
907
|
+
{
|
|
908
|
+
return new DateApiExtension(new Date(this._originalValue), null, this._localeSvc);
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
public diffMonths(date: Date): number
|
|
912
|
+
{
|
|
913
|
+
return differenceInMonths(this._value, date);
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
public diffYears(date: Date): number
|
|
917
|
+
{
|
|
918
|
+
return differenceInYears(this._value, date);
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
public diffSeconds(date: Date): number
|
|
922
|
+
{
|
|
923
|
+
return differenceInSeconds(this._value, date);
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
```
|
|
927
|
+
|
|
928
|
+
Register the extension globally:
|
|
929
|
+
|
|
930
|
+
```typescript
|
|
931
|
+
import {DATE_API_OBJECT_TYPE} from '@anglr/datetime';
|
|
932
|
+
|
|
933
|
+
{
|
|
934
|
+
provide: DATE_API_OBJECT_TYPE,
|
|
935
|
+
useValue: DateApiExtension,
|
|
936
|
+
}
|
|
937
|
+
```
|
|
938
|
+
|
|
939
|
+
### Feature Module Pattern
|
|
940
|
+
|
|
941
|
+
```typescript
|
|
942
|
+
import {NgModule} from '@angular/core';
|
|
943
|
+
import {ReactiveFormsModule} from '@angular/forms';
|
|
944
|
+
import {
|
|
945
|
+
DateTimeModule,
|
|
946
|
+
WithNowDirective,
|
|
947
|
+
WithTimeDirective,
|
|
948
|
+
WithTodayDirective,
|
|
949
|
+
DateTimePickerModule,
|
|
950
|
+
DatePickerInputDirective,
|
|
951
|
+
DateTimePickerInputDirective,
|
|
952
|
+
DateTimeInputHandlerDirective,
|
|
953
|
+
SimpleDatePickerInputDirective,
|
|
954
|
+
SimpleDateTimePickerInputDirective,
|
|
955
|
+
SimpleDateTimeInputHandlerDirective,
|
|
956
|
+
} from '@anglr/datetime';
|
|
957
|
+
|
|
958
|
+
@NgModule(
|
|
959
|
+
{
|
|
960
|
+
imports:
|
|
961
|
+
[
|
|
962
|
+
WithNowDirective,
|
|
963
|
+
WithTimeDirective,
|
|
964
|
+
WithTodayDirective,
|
|
965
|
+
DatePickerInputDirective,
|
|
966
|
+
DateTimePickerInputDirective,
|
|
967
|
+
DateTimeInputHandlerDirective,
|
|
968
|
+
SimpleDatePickerInputDirective,
|
|
969
|
+
SimpleDateTimePickerInputDirective,
|
|
970
|
+
SimpleDateTimeInputHandlerDirective,
|
|
971
|
+
],
|
|
972
|
+
exports:
|
|
973
|
+
[
|
|
974
|
+
DateTimeModule,
|
|
975
|
+
WithNowDirective,
|
|
976
|
+
WithTimeDirective,
|
|
977
|
+
WithTodayDirective,
|
|
978
|
+
ReactiveFormsModule,
|
|
979
|
+
DateTimePickerModule,
|
|
980
|
+
DatePickerInputDirective,
|
|
981
|
+
DateTimePickerInputDirective,
|
|
982
|
+
DateTimeInputHandlerDirective,
|
|
983
|
+
SimpleDatePickerInputDirective,
|
|
984
|
+
SimpleDateTimePickerInputDirective,
|
|
985
|
+
SimpleDateTimeInputHandlerDirective,
|
|
986
|
+
],
|
|
987
|
+
})
|
|
988
|
+
export class FormsFeatureModule
|
|
989
|
+
{
|
|
990
|
+
}
|
|
991
|
+
```
|
|
992
|
+
|
|
993
|
+
### Display Feature Module with Pipes
|
|
994
|
+
|
|
995
|
+
```typescript
|
|
996
|
+
import {NgModule} from '@angular/core';
|
|
997
|
+
import {CommonModule} from '@angular/common';
|
|
998
|
+
import {DatePipesModule} from '@anglr/datetime';
|
|
999
|
+
|
|
1000
|
+
@NgModule(
|
|
1001
|
+
{
|
|
1002
|
+
exports:
|
|
1003
|
+
[
|
|
1004
|
+
CommonModule,
|
|
1005
|
+
DatePipesModule,
|
|
1006
|
+
],
|
|
1007
|
+
})
|
|
1008
|
+
export class DisplayingFeatureModule
|
|
1009
|
+
{
|
|
1010
|
+
}
|
|
1011
|
+
```
|
|
1012
|
+
|
|
1013
|
+
---
|
|
1014
|
+
|
|
1015
|
+
## Samples
|
|
1016
|
+
|
|
1017
|
+
These samples demonstrate the building-block approach using individual directives. Live demos are available at [Samples](https://ressurectit.github.io/#/content/datetime#samples).
|
|
1018
|
+
|
|
1019
|
+
### Basic DateTime Input
|
|
1020
|
+
|
|
1021
|
+
A minimal date input using `dateTime` and `dateTimeInput` directives with a reactive form control.
|
|
1022
|
+
|
|
1023
|
+
```typescript
|
|
1024
|
+
import {Component, ChangeDetectionStrategy} from '@angular/core';
|
|
1025
|
+
import {FormControl, ReactiveFormsModule} from '@angular/forms';
|
|
1026
|
+
import {JsonPipe} from '@angular/common';
|
|
1027
|
+
import {DatePipesModule, DateTimeModule} from '@anglr/datetime';
|
|
1028
|
+
|
|
1029
|
+
@Component(
|
|
1030
|
+
{
|
|
1031
|
+
selector: 'basic-sample',
|
|
1032
|
+
templateUrl: 'basicSample.component.html',
|
|
1033
|
+
imports:
|
|
1034
|
+
[
|
|
1035
|
+
ReactiveFormsModule,
|
|
1036
|
+
DatePipesModule,
|
|
1037
|
+
DateTimeModule,
|
|
1038
|
+
JsonPipe,
|
|
1039
|
+
],
|
|
1040
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
1041
|
+
})
|
|
1042
|
+
export class BasicSampleComponent
|
|
1043
|
+
{
|
|
1044
|
+
protected datetimeControl: FormControl<unknown> = new FormControl(null);
|
|
1045
|
+
}
|
|
1046
|
+
```
|
|
1047
|
+
|
|
1048
|
+
```html
|
|
1049
|
+
<div class="flex-row margin-bottom-extra-small">
|
|
1050
|
+
<div class="flex-1">Raw value: {{datetimeControl.value | json}}</div>
|
|
1051
|
+
<div class="flex-1">Date value: {{datetimeControl.value | dateFormat}}</div>
|
|
1052
|
+
</div>
|
|
1053
|
+
|
|
1054
|
+
<input class="form-control" dateTime dateTimeInput [formControl]="datetimeControl">
|
|
1055
|
+
```
|
|
1056
|
+
|
|
1057
|
+
### Basic DateTime Picker
|
|
1058
|
+
|
|
1059
|
+
Adds a date picker popup by applying the `withPicker` directive.
|
|
1060
|
+
|
|
1061
|
+
```typescript
|
|
1062
|
+
import {Component, ChangeDetectionStrategy} from '@angular/core';
|
|
1063
|
+
import {FormControl, ReactiveFormsModule} from '@angular/forms';
|
|
1064
|
+
import {JsonPipe} from '@angular/common';
|
|
1065
|
+
import {DatePipesModule, DateTimeModule, DateTimePickerModule} from '@anglr/datetime';
|
|
1066
|
+
|
|
1067
|
+
@Component(
|
|
1068
|
+
{
|
|
1069
|
+
selector: 'basic-picker-sample',
|
|
1070
|
+
templateUrl: 'basicPickerSample.component.html',
|
|
1071
|
+
imports:
|
|
1072
|
+
[
|
|
1073
|
+
DateTimePickerModule,
|
|
1074
|
+
ReactiveFormsModule,
|
|
1075
|
+
DatePipesModule,
|
|
1076
|
+
DateTimeModule,
|
|
1077
|
+
JsonPipe,
|
|
1078
|
+
],
|
|
1079
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
1080
|
+
})
|
|
1081
|
+
export class BasicPickerSampleComponent
|
|
1082
|
+
{
|
|
1083
|
+
protected datetimeControl: FormControl<unknown> = new FormControl(null);
|
|
1084
|
+
}
|
|
1085
|
+
```
|
|
1086
|
+
|
|
1087
|
+
```html
|
|
1088
|
+
<div class="flex-row margin-bottom-extra-small">
|
|
1089
|
+
<div class="flex-1">Raw value: {{datetimeControl.value | json}}</div>
|
|
1090
|
+
<div class="flex-1">Date value: {{datetimeControl.value | dateFormat}}</div>
|
|
1091
|
+
</div>
|
|
1092
|
+
|
|
1093
|
+
<input class="form-control" dateTime dateTimeInput withPicker [formControl]="datetimeControl">
|
|
1094
|
+
```
|
|
1095
|
+
|
|
1096
|
+
### DateTime with Time
|
|
1097
|
+
|
|
1098
|
+
Enables time selection alongside date by adding the `withTime` directive.
|
|
1099
|
+
|
|
1100
|
+
```typescript
|
|
1101
|
+
import {Component, ChangeDetectionStrategy} from '@angular/core';
|
|
1102
|
+
import {FormControl, ReactiveFormsModule} from '@angular/forms';
|
|
1103
|
+
import {JsonPipe} from '@angular/common';
|
|
1104
|
+
import {DatePipesModule, DateTimeModule, DateTimePickerModule, WithTimeDirective} from '@anglr/datetime';
|
|
1105
|
+
|
|
1106
|
+
@Component(
|
|
1107
|
+
{
|
|
1108
|
+
selector: 'with-time-sample',
|
|
1109
|
+
templateUrl: 'withTimeSample.component.html',
|
|
1110
|
+
imports:
|
|
1111
|
+
[
|
|
1112
|
+
DateTimePickerModule,
|
|
1113
|
+
WithTimeDirective,
|
|
1114
|
+
ReactiveFormsModule,
|
|
1115
|
+
DatePipesModule,
|
|
1116
|
+
DateTimeModule,
|
|
1117
|
+
JsonPipe,
|
|
1118
|
+
],
|
|
1119
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
1120
|
+
})
|
|
1121
|
+
export class WithTimeSampleComponent
|
|
1122
|
+
{
|
|
1123
|
+
protected datetimeControl: FormControl<unknown> = new FormControl(null);
|
|
1124
|
+
}
|
|
1125
|
+
```
|
|
1126
|
+
|
|
1127
|
+
```html
|
|
1128
|
+
<div class="flex-row margin-bottom-extra-small">
|
|
1129
|
+
<div class="flex-1">Raw value: {{datetimeControl.value | json}}</div>
|
|
1130
|
+
<div class="flex-1">Date value: {{datetimeControl.value | dateFormat: 'dateTime'}}</div>
|
|
1131
|
+
</div>
|
|
1132
|
+
|
|
1133
|
+
<input class="form-control" dateTime dateTimeInput withPicker withTime [formControl]="datetimeControl">
|
|
1134
|
+
```
|
|
1135
|
+
|
|
1136
|
+
### Today vs Now
|
|
1137
|
+
|
|
1138
|
+
Compares `withToday` (sets value to start of day) and `withNow` (sets value to current date/time) when the input is focused while empty.
|
|
1139
|
+
|
|
1140
|
+
```typescript
|
|
1141
|
+
import {Component, ChangeDetectionStrategy} from '@angular/core';
|
|
1142
|
+
import {FormControl, ReactiveFormsModule} from '@angular/forms';
|
|
1143
|
+
import {JsonPipe} from '@angular/common';
|
|
1144
|
+
import {DatePipesModule, DateTimeModule, DateTimePickerModule, WithNowDirective, WithTimeDirective, WithTodayDirective} from '@anglr/datetime';
|
|
1145
|
+
|
|
1146
|
+
@Component(
|
|
1147
|
+
{
|
|
1148
|
+
selector: 'today-vs-now-sample',
|
|
1149
|
+
templateUrl: 'todayVsNowSample.component.html',
|
|
1150
|
+
imports:
|
|
1151
|
+
[
|
|
1152
|
+
WithTimeDirective,
|
|
1153
|
+
WithTodayDirective,
|
|
1154
|
+
DateTimePickerModule,
|
|
1155
|
+
ReactiveFormsModule,
|
|
1156
|
+
WithNowDirective,
|
|
1157
|
+
DatePipesModule,
|
|
1158
|
+
DateTimeModule,
|
|
1159
|
+
JsonPipe,
|
|
1160
|
+
],
|
|
1161
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
1162
|
+
})
|
|
1163
|
+
export class TodayVsNowSampleComponent
|
|
1164
|
+
{
|
|
1165
|
+
protected datetimeControl: FormControl<unknown> = new FormControl(null);
|
|
1166
|
+
protected datetimeControl2: FormControl<unknown> = new FormControl(null);
|
|
1167
|
+
}
|
|
1168
|
+
```
|
|
1169
|
+
|
|
1170
|
+
```html
|
|
1171
|
+
<div class="flex-row column-gap-small margin-bottom-extra-small">
|
|
1172
|
+
<div class="flex-1">
|
|
1173
|
+
<div>Raw value: {{datetimeControl.value | json}}</div>
|
|
1174
|
+
<div>Date value: {{datetimeControl.value | dateFormat: 'dateTime'}}</div>
|
|
1175
|
+
</div>
|
|
1176
|
+
|
|
1177
|
+
<div class="flex-1">
|
|
1178
|
+
<div>Raw value: {{datetimeControl2.value | json}}</div>
|
|
1179
|
+
<div>Date value: {{datetimeControl2.value | dateFormat: 'dateTime'}}</div>
|
|
1180
|
+
</div>
|
|
1181
|
+
</div>
|
|
1182
|
+
|
|
1183
|
+
<div class="flex-row column-gap-small">
|
|
1184
|
+
<div class="form-group flex-1">
|
|
1185
|
+
<label class="control-label">today</label>
|
|
1186
|
+
<input class="form-control" dateTime dateTimeInput withPicker withTime withToday [formControl]="datetimeControl">
|
|
1187
|
+
</div>
|
|
1188
|
+
|
|
1189
|
+
<div class="form-group flex-1">
|
|
1190
|
+
<label class="control-label">now</label>
|
|
1191
|
+
<input class="form-control" dateTime dateTimeInput withPicker withTime withNow [formControl]="datetimeControl2">
|
|
1192
|
+
</div>
|
|
1193
|
+
</div>
|
|
1194
|
+
```
|
|
1195
|
+
|
|
1196
|
+
### Input Handlers
|
|
1197
|
+
|
|
1198
|
+
Demonstrates the difference between `withSimpleHandler` (simple arrow key navigation: ±1 day/±1 week) and `withHandler` (advanced segment-based keyboard navigation).
|
|
1199
|
+
|
|
1200
|
+
```typescript
|
|
1201
|
+
import {Component, ChangeDetectionStrategy} from '@angular/core';
|
|
1202
|
+
import {FormControl, ReactiveFormsModule} from '@angular/forms';
|
|
1203
|
+
import {JsonPipe} from '@angular/common';
|
|
1204
|
+
import {DatePipesModule, DateTimeInputHandlerDirective, DateTimeModule, DateTimePickerModule, SimpleDateTimeInputHandlerDirective} from '@anglr/datetime';
|
|
1205
|
+
|
|
1206
|
+
@Component(
|
|
1207
|
+
{
|
|
1208
|
+
selector: 'handlers-sample',
|
|
1209
|
+
templateUrl: 'handlersSample.component.html',
|
|
1210
|
+
imports:
|
|
1211
|
+
[
|
|
1212
|
+
SimpleDateTimeInputHandlerDirective,
|
|
1213
|
+
DateTimeInputHandlerDirective,
|
|
1214
|
+
DateTimePickerModule,
|
|
1215
|
+
ReactiveFormsModule,
|
|
1216
|
+
DatePipesModule,
|
|
1217
|
+
DateTimeModule,
|
|
1218
|
+
JsonPipe,
|
|
1219
|
+
],
|
|
1220
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
1221
|
+
})
|
|
1222
|
+
export class HandlersSampleComponent
|
|
1223
|
+
{
|
|
1224
|
+
protected datetimeControl: FormControl<unknown> = new FormControl(null);
|
|
1225
|
+
protected datetimeControl2: FormControl<unknown> = new FormControl(null);
|
|
1226
|
+
}
|
|
1227
|
+
```
|
|
1228
|
+
|
|
1229
|
+
```html
|
|
1230
|
+
<div class="flex-row column-gap-small margin-bottom-extra-small">
|
|
1231
|
+
<div class="flex-1">
|
|
1232
|
+
<div>Raw value: {{datetimeControl.value | json}}</div>
|
|
1233
|
+
<div>Date value: {{datetimeControl.value | dateFormat}}</div>
|
|
1234
|
+
</div>
|
|
1235
|
+
|
|
1236
|
+
<div class="flex-1">
|
|
1237
|
+
<div>Raw value: {{datetimeControl2.value | json}}</div>
|
|
1238
|
+
<div>Date value: {{datetimeControl2.value | dateFormat}}</div>
|
|
1239
|
+
</div>
|
|
1240
|
+
</div>
|
|
1241
|
+
|
|
1242
|
+
<div class="flex-row column-gap-small">
|
|
1243
|
+
<div class="form-group flex-1">
|
|
1244
|
+
<label class="control-label">simple handler</label>
|
|
1245
|
+
<input class="form-control" dateTime dateTimeInput withPicker withSimpleHandler [formControl]="datetimeControl">
|
|
1246
|
+
</div>
|
|
1247
|
+
|
|
1248
|
+
<div class="form-group flex-1">
|
|
1249
|
+
<label class="control-label">handler</label>
|
|
1250
|
+
<input class="form-control" dateTime dateTimeInput withPicker withHandler [formControl]="datetimeControl2">
|
|
1251
|
+
</div>
|
|
1252
|
+
</div>
|
|
1253
|
+
```
|
|
1254
|
+
|
|
1255
|
+
### Different Data Types
|
|
1256
|
+
|
|
1257
|
+
Shows how to use different `valueFormat` options to control the output type of the form control value.
|
|
1258
|
+
|
|
1259
|
+
```typescript
|
|
1260
|
+
import {Component, ChangeDetectionStrategy} from '@angular/core';
|
|
1261
|
+
import {FormControl, ReactiveFormsModule} from '@angular/forms';
|
|
1262
|
+
import {JsonPipe} from '@angular/common';
|
|
1263
|
+
import {DatePipesModule, DateTimeModule, DateTimePickerModule} from '@anglr/datetime';
|
|
1264
|
+
|
|
1265
|
+
@Component(
|
|
1266
|
+
{
|
|
1267
|
+
selector: 'data-types-sample',
|
|
1268
|
+
templateUrl: 'dataTypesSample.component.html',
|
|
1269
|
+
imports:
|
|
1270
|
+
[
|
|
1271
|
+
DateTimePickerModule,
|
|
1272
|
+
ReactiveFormsModule,
|
|
1273
|
+
DatePipesModule,
|
|
1274
|
+
DateTimeModule,
|
|
1275
|
+
JsonPipe,
|
|
1276
|
+
],
|
|
1277
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
1278
|
+
})
|
|
1279
|
+
export class DataTypesSampleComponent
|
|
1280
|
+
{
|
|
1281
|
+
protected datetimeControl: FormControl<unknown> = new FormControl(null);
|
|
1282
|
+
protected timestampControl: FormControl<number|null> = new FormControl(null);
|
|
1283
|
+
protected stringControl: FormControl<string|null> = new FormControl(null);
|
|
1284
|
+
protected customStringControl: FormControl<string|null> = new FormControl(null);
|
|
1285
|
+
}
|
|
1286
|
+
```
|
|
1287
|
+
|
|
1288
|
+
```html
|
|
1289
|
+
<div class="flex-row column-gap-medium margin-bottom-extra-small">
|
|
1290
|
+
<div class="flex-1">
|
|
1291
|
+
<div>Raw value: {{datetimeControl.value | json}}</div>
|
|
1292
|
+
<div>Date value: {{datetimeControl.value | dateFormat}}</div>
|
|
1293
|
+
</div>
|
|
1294
|
+
|
|
1295
|
+
<div class="flex-1">
|
|
1296
|
+
<div>Raw value: {{timestampControl.value | json}}</div>
|
|
1297
|
+
<div>Date value: {{timestampControl.value | dateFormat}}</div>
|
|
1298
|
+
</div>
|
|
1299
|
+
|
|
1300
|
+
<div class="flex-1">
|
|
1301
|
+
<div>Raw value: {{stringControl.value | json}}</div>
|
|
1302
|
+
<div>Date value: {{stringControl.value | dateFormat: 'date' : 'yyyyMMdd'}}</div>
|
|
1303
|
+
</div>
|
|
1304
|
+
|
|
1305
|
+
<div class="flex-1">
|
|
1306
|
+
<div>Raw value: {{customStringControl.value | json}}</div>
|
|
1307
|
+
<div>Date value: {{customStringControl.value | dateFormat: 'date' : 'yyyy-MM-dd'}}</div>
|
|
1308
|
+
</div>
|
|
1309
|
+
</div>
|
|
1310
|
+
|
|
1311
|
+
<div class="flex-row column-gap-medium">
|
|
1312
|
+
<div class="form-group flex-1">
|
|
1313
|
+
<label class="control-label">type DateInstance</label>
|
|
1314
|
+
<input class="form-control" dateTime dateTimeInput withPicker [formControl]="datetimeControl" valueFormat="DateInstance">
|
|
1315
|
+
</div>
|
|
1316
|
+
|
|
1317
|
+
<div class="form-group flex-1">
|
|
1318
|
+
<label class="control-label">type UnixTimestamp</label>
|
|
1319
|
+
<input class="form-control" dateTime dateTimeInput withPicker [formControl]="timestampControl" valueFormat="Timestamp">
|
|
1320
|
+
</div>
|
|
1321
|
+
|
|
1322
|
+
<div class="form-group flex-1">
|
|
1323
|
+
<label class="control-label">type FormattedString</label>
|
|
1324
|
+
<input class="form-control" dateTime dateTimeInput withPicker [formControl]="stringControl" valueFormat="FormattedString" customFormat="yyyyMMdd">
|
|
1325
|
+
</div>
|
|
1326
|
+
|
|
1327
|
+
<div class="form-group flex-1">
|
|
1328
|
+
<label class="control-label">type DataString</label>
|
|
1329
|
+
<input class="form-control" dateTime dateTimeInput withPicker [formControl]="customStringControl" valueFormat="DataString" dataFormat="yyyy-MM-dd">
|
|
1330
|
+
</div>
|
|
1331
|
+
</div>
|
|
1332
|
+
```
|
|
1333
|
+
|
|
1334
|
+
### Customized Picker
|
|
1335
|
+
|
|
1336
|
+
Customizes the picker to show only month/year periods with a custom date format.
|
|
1337
|
+
|
|
1338
|
+
```typescript
|
|
1339
|
+
import {Component, ChangeDetectionStrategy} from '@angular/core';
|
|
1340
|
+
import {FormControl, ReactiveFormsModule} from '@angular/forms';
|
|
1341
|
+
import {JsonPipe} from '@angular/common';
|
|
1342
|
+
import {DatePipesModule, DateTimeModule, DateTimePickerModule, DateTimePickerOptions, MonthPickerComponent, YearPickerComponent} from '@anglr/datetime';
|
|
1343
|
+
|
|
1344
|
+
@Component(
|
|
1345
|
+
{
|
|
1346
|
+
selector: 'customized-picker-sample',
|
|
1347
|
+
templateUrl: 'customizedPickerSample.component.html',
|
|
1348
|
+
imports:
|
|
1349
|
+
[
|
|
1350
|
+
DateTimePickerModule,
|
|
1351
|
+
ReactiveFormsModule,
|
|
1352
|
+
DatePipesModule,
|
|
1353
|
+
DateTimeModule,
|
|
1354
|
+
JsonPipe,
|
|
1355
|
+
],
|
|
1356
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
1357
|
+
})
|
|
1358
|
+
export class CustomizedPickerSampleComponent
|
|
1359
|
+
{
|
|
1360
|
+
protected datetimeControl: FormControl<unknown> = new FormControl(null);
|
|
1361
|
+
protected pickerOptions: Partial<DateTimePickerOptions<unknown>>;
|
|
1362
|
+
|
|
1363
|
+
constructor()
|
|
1364
|
+
{
|
|
1365
|
+
this.pickerOptions =
|
|
1366
|
+
{
|
|
1367
|
+
periodsDefinition:
|
|
1368
|
+
{
|
|
1369
|
+
month: MonthPickerComponent,
|
|
1370
|
+
year: YearPickerComponent,
|
|
1371
|
+
},
|
|
1372
|
+
defaultPeriod: 'month',
|
|
1373
|
+
};
|
|
1374
|
+
}
|
|
1375
|
+
}
|
|
1376
|
+
```
|
|
1377
|
+
|
|
1378
|
+
```html
|
|
1379
|
+
<div class="flex-row margin-bottom-extra-small">
|
|
1380
|
+
<div class="flex-1">Raw value: {{datetimeControl.value | json}}</div>
|
|
1381
|
+
<div class="flex-1">Date value: {{datetimeControl.value | dateFormat: 'date': 'yyyyMM'}}</div>
|
|
1382
|
+
</div>
|
|
1383
|
+
|
|
1384
|
+
<input class="form-control" dateTime dateTimeInput withPicker [formControl]="datetimeControl" [pickerOptions]="pickerOptions" valueFormat="FormattedString" customFormat="yyyyMM">
|
|
1385
|
+
```
|
|
1386
|
+
|
|
1387
|
+
---
|
|
1388
|
+
|
|
1389
|
+
## Advanced Usage
|
|
1390
|
+
|
|
1391
|
+
### Relative Date Input
|
|
1392
|
+
|
|
1393
|
+
Users can type relative expressions in inputs configured with `DateTimeRelativeParser`:
|
|
1394
|
+
|
|
1395
|
+
| Expression | Result |
|
|
1396
|
+
|------------|--------|
|
|
1397
|
+
| `+5d` | Today + 5 days |
|
|
1398
|
+
| `-2M` | Today - 2 months |
|
|
1399
|
+
| `+1y` | Today + 1 year |
|
|
1400
|
+
| `-3w` | Today - 3 weeks |
|
|
1401
|
+
| `+2h` | Now + 2 hours |
|
|
1402
|
+
| `-30m` | Now - 30 minutes |
|
|
1403
|
+
|
|
1404
|
+
### DateTimeValue Interface (Ranges)
|
|
1405
|
+
|
|
1406
|
+
```typescript
|
|
1407
|
+
import {DateTimeValue} from '@anglr/datetime';
|
|
1408
|
+
|
|
1409
|
+
// Represents a date range
|
|
1410
|
+
const period: DateTimeValue<Date> =
|
|
1411
|
+
{
|
|
1412
|
+
from: new Date(2024, 0, 1),
|
|
1413
|
+
to: new Date(2024, 11, 31),
|
|
1414
|
+
};
|
|
1415
|
+
```
|
|
1416
|
+
|
|
1417
|
+
### Using DateApi in Services
|
|
1418
|
+
|
|
1419
|
+
```typescript
|
|
1420
|
+
import {inject, Injectable} from '@angular/core';
|
|
1421
|
+
import {DATE_API, DateApi} from '@anglr/datetime';
|
|
1422
|
+
|
|
1423
|
+
@Injectable(
|
|
1424
|
+
{
|
|
1425
|
+
providedIn: 'root',
|
|
1426
|
+
})
|
|
1427
|
+
export class MyDateService
|
|
1428
|
+
{
|
|
1429
|
+
private readonly dateApi: DateApi<Date> = inject<DateApi<Date>>(DATE_API);
|
|
1430
|
+
|
|
1431
|
+
public isExpired(dateStr: string): boolean
|
|
1432
|
+
{
|
|
1433
|
+
const date = this.dateApi.getValue(dateStr, 'yyyy-MM-dd');
|
|
1434
|
+
const now = this.dateApi.now();
|
|
1435
|
+
|
|
1436
|
+
return date.isBefore(now.value);
|
|
1437
|
+
}
|
|
1438
|
+
|
|
1439
|
+
public getMonthRange(date: Date): {from: string; to: string}
|
|
1440
|
+
{
|
|
1441
|
+
const obj = this.dateApi.getValue(date);
|
|
1442
|
+
|
|
1443
|
+
return {
|
|
1444
|
+
from: obj.clone().startOfMonth().format('yyyy-MM-dd'),
|
|
1445
|
+
to: obj.clone().endOfMonth().format('yyyy-MM-dd'),
|
|
1446
|
+
};
|
|
1447
|
+
}
|
|
1448
|
+
|
|
1449
|
+
public formatForDisplay(date: Date): string
|
|
1450
|
+
{
|
|
1451
|
+
return this.dateApi.getValue(date).format('d.M.yyyy HH:mm');
|
|
1452
|
+
}
|
|
1453
|
+
}
|
|
1454
|
+
```
|
|
1455
|
+
|
|
1456
|
+
---
|
|
1457
|
+
|
|
1458
|
+
## License
|
|
1459
|
+
|
|
1460
|
+
[MIT](LICENSE)
|