ngxsmk-datepicker 2.3.1 → 2.4.0

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/docs/signals.md CHANGED
@@ -1,266 +1,266 @@
1
- # Signals Integration Guide
2
-
3
- **Last updated:** June 3, 2026 - **Current stable:** v2.3.1
4
-
5
- ngxsmk-datepicker is fully compatible with Angular Signals, providing seamless integration with both traditional reactive forms and modern signal-based patterns.
6
-
7
- ## Basic Signal Binding
8
-
9
- ### Using Writable Signals
10
-
11
- The simplest way to use signals is with a writable signal and two-way binding:
12
-
13
- ```typescript
14
- import { Component, signal } from '@angular/core';
15
- import { NgxsmkDatepickerComponent, DatepickerValue } from 'ngxsmk-datepicker';
16
-
17
- @Component({
18
- selector: 'app-example',
19
- standalone: true,
20
- imports: [NgxsmkDatepickerComponent],
21
- template: `
22
- <ngxsmk-datepicker
23
- mode="single"
24
- [value]="selectedDate()"
25
- (valueChange)="selectedDate.set($event)">
26
- </ngxsmk-datepicker>
27
-
28
- <p>Selected: {{ selectedDate() | json }}</p>
29
- `
30
- })
31
- export class ExampleComponent {
32
- selectedDate = signal<DatepickerValue>(null);
33
- }
34
- ```
35
-
36
- ### Using Computed Signals
37
-
38
- You can derive values from signals:
39
-
40
- ```typescript
41
- import { Component, signal, computed } from '@angular/core';
42
-
43
- @Component({
44
- // ...
45
- })
46
- export class ExampleComponent {
47
- selectedDate = signal<DatepickerValue>(null);
48
-
49
- // Computed value based on selected date
50
- formattedDate = computed(() => {
51
- const date = this.selectedDate();
52
- if (!date) return 'No date selected';
53
- if (date instanceof Date) {
54
- return date.toLocaleDateString();
55
- }
56
- return 'Invalid date';
57
- });
58
- }
59
- ```
60
-
61
- ## Signal Forms (Angular 21+)
62
-
63
- ### Using the `[field]` Input
64
-
65
- For Angular 21+ Signal Forms, use the `[field]` input for direct integration. The datepicker automatically tracks dirty state when using this binding:
66
-
67
- ```typescript
68
- import { Component, signal, form, objectSchema } from '@angular/core';
69
- import { NgxsmkDatepickerComponent } from 'ngxsmk-datepicker';
70
-
71
- @Component({
72
- selector: 'app-form',
73
- standalone: true,
74
- imports: [NgxsmkDatepickerComponent],
75
- template: `
76
- <form>
77
- <ngxsmk-datepicker
78
- [field]="myForm.dateInQuestion"
79
- mode="single"
80
- placeholder="Select a date">
81
- </ngxsmk-datepicker>
82
-
83
- <button [disabled]="!myForm().dirty()">Save</button>
84
- </form>
85
- `
86
- })
87
- export class FormComponent {
88
- localObject = signal({
89
- dateInQuestion: new Date()
90
- });
91
-
92
- myForm = form(this.localObject, objectSchema({
93
- dateInQuestion: objectSchema<Date>()
94
- }));
95
- }
96
- ```
97
-
98
- **Important**: The `[field]` binding automatically tracks dirty state. Avoid mixing it with manual `(valueChange)` handlers that bypass the form API, as this may prevent proper dirty tracking. See the [Signal Forms Integration Guide](signal-forms.md) for detailed documentation.
99
-
100
- ### Manual Signal Updates
101
-
102
- If you need more control, you can manually update signals:
103
-
104
- ```typescript
105
- import { Component, signal, effect } from '@angular/core';
106
-
107
- @Component({
108
- // ...
109
- })
110
- export class ExampleComponent {
111
- selectedDate = signal<DatepickerValue>(null);
112
-
113
- constructor() {
114
- // React to date changes
115
- effect(() => {
116
- const date = this.selectedDate();
117
- if (date) {
118
- console.log('Date changed:', date);
119
- // Perform side effects like API calls
120
- }
121
- });
122
- }
123
-
124
- onDateChange(newDate: DatepickerValue) {
125
- this.selectedDate.set(newDate);
126
- // Additional logic here
127
- }
128
- }
129
- ```
130
-
131
- ## httpResource Integration
132
-
133
- The datepicker works seamlessly with `httpResource` for server-side data:
134
-
135
- ```typescript
136
- import { Component, inject } from '@angular/core';
137
- import { httpResource } from '@angular/common/http';
138
- import { signal, linkedSignal } from '@angular/core';
139
-
140
- @Component({
141
- // ...
142
- })
143
- export class DataComponent {
144
- private http = inject(HttpClient);
145
-
146
- // Create a resource that fetches data
147
- resource = httpResource({
148
- request: () => this.http.get<{ dateInQuestion: Date }>('/api/data'),
149
- loader: signal(false)
150
- });
151
-
152
- // Link the response to a signal
153
- localObject = linkedSignal(() => this.resource.response.value());
154
-
155
- // Compute the date from the response
156
- myDate = computed(() => {
157
- const obj = this.localObject();
158
- return obj?.dateInQuestion ? new Date(obj.dateInQuestion) : null;
159
- });
160
-
161
- // Update the datepicker when data arrives
162
- updateDate(newDate: DatepickerValue) {
163
- // Update your resource or local signal
164
- this.localObject.update(obj => ({
165
- ...obj,
166
- dateInQuestion: newDate
167
- }));
168
- }
169
- }
170
- ```
171
-
172
- ```html
173
- <ngxsmk-datepicker
174
- [value]="myDate()"
175
- (valueChange)="updateDate($event)"
176
- mode="single">
177
- </ngxsmk-datepicker>
178
- ```
179
-
180
- ## Range Selection with Signals
181
-
182
- For date ranges, use signals with range objects:
183
-
184
- ```typescript
185
- import { Component, signal } from '@angular/core';
186
-
187
- @Component({
188
- // ...
189
- })
190
- export class RangeComponent {
191
- dateRange = signal<{ start: Date; end: Date } | null>(null);
192
-
193
- onRangeChange(range: { start: Date; end: Date } | null) {
194
- this.dateRange.set(range);
195
- }
196
- }
197
- ```
198
-
199
- ```html
200
- <ngxsmk-datepicker
201
- mode="range"
202
- [value]="dateRange()"
203
- (valueChange)="dateRange.set($event)">
204
- </ngxsmk-datepicker>
205
- ```
206
-
207
- ## Multiple Date Selection
208
-
209
- For multiple date selection:
210
-
211
- ```typescript
212
- import { Component, signal } from '@angular/core';
213
-
214
- @Component({
215
- // ...
216
- })
217
- export class MultipleComponent {
218
- selectedDates = signal<Date[]>([]);
219
- }
220
- ```
221
-
222
- ```html
223
- <ngxsmk-datepicker
224
- mode="multiple"
225
- [value]="selectedDates()"
226
- (valueChange)="selectedDates.set($event)">
227
- </ngxsmk-datepicker>
228
- ```
229
-
230
- ## Best Practices
231
-
232
- 1. **Use `signal()` for local state**: For component-local date selection, use writable signals.
233
-
234
- 2. **Use `[field]` for forms**: When using Angular Signal Forms, prefer the `[field]` input for automatic synchronization and dirty state tracking.
235
-
236
- 3. **Avoid mixing `[field]` with manual handlers**: Don't use both `[field]` and `(valueChange)` together, as the manual handler may bypass form dirty tracking.
237
-
238
- 4. **Use `computed()` for derived values**: Derive formatted dates, validation states, or other computed properties.
239
-
240
- 5. **Handle null values**: Always check for null/undefined when working with datepicker values.
241
-
242
- 6. **Type safety**: Use the `DatepickerValue` type for better TypeScript support:
243
- ```typescript
244
- import { DatepickerValue } from 'ngxsmk-datepicker';
245
- ```
246
-
247
- For detailed Signal Forms integration including dirty state tracking, see the [Signal Forms Integration Guide](signal-forms.md).
248
-
249
- ## Migration from Reactive Forms
250
-
251
- If you're migrating from Reactive Forms to Signals:
252
-
253
- **Before (Reactive Forms):**
254
- ```typescript
255
- dateControl = new FormControl<DatepickerValue>(null);
256
- ```
257
-
258
- **After (Signals):**
259
- ```typescript
260
- dateSignal = signal<DatepickerValue>(null);
261
- ```
262
-
263
- The datepicker supports both patterns simultaneously, so you can migrate gradually.
264
-
265
-
266
-
1
+ # Signals Integration Guide
2
+
3
+ **Last updated:** July 2, 2026 - **Current stable:** v2.4.0
4
+
5
+ ngxsmk-datepicker is fully compatible with Angular Signals, providing seamless integration with both traditional reactive forms and modern signal-based patterns.
6
+
7
+ ## Basic Signal Binding
8
+
9
+ ### Using Writable Signals
10
+
11
+ The simplest way to use signals is with a writable signal and two-way binding:
12
+
13
+ ```typescript
14
+ import { Component, signal } from '@angular/core';
15
+ import { NgxsmkDatepickerComponent, DatepickerValue } from 'ngxsmk-datepicker';
16
+
17
+ @Component({
18
+ selector: 'app-example',
19
+ standalone: true,
20
+ imports: [NgxsmkDatepickerComponent],
21
+ template: `
22
+ <ngxsmk-datepicker
23
+ mode="single"
24
+ [value]="selectedDate()"
25
+ (valueChange)="selectedDate.set($event)">
26
+ </ngxsmk-datepicker>
27
+
28
+ <p>Selected: {{ selectedDate() | json }}</p>
29
+ `
30
+ })
31
+ export class ExampleComponent {
32
+ selectedDate = signal<DatepickerValue>(null);
33
+ }
34
+ ```
35
+
36
+ ### Using Computed Signals
37
+
38
+ You can derive values from signals:
39
+
40
+ ```typescript
41
+ import { Component, signal, computed } from '@angular/core';
42
+
43
+ @Component({
44
+ // ...
45
+ })
46
+ export class ExampleComponent {
47
+ selectedDate = signal<DatepickerValue>(null);
48
+
49
+ // Computed value based on selected date
50
+ formattedDate = computed(() => {
51
+ const date = this.selectedDate();
52
+ if (!date) return 'No date selected';
53
+ if (date instanceof Date) {
54
+ return date.toLocaleDateString();
55
+ }
56
+ return 'Invalid date';
57
+ });
58
+ }
59
+ ```
60
+
61
+ ## Signal Forms (Angular 21+)
62
+
63
+ ### Using the `[field]` Input
64
+
65
+ For Angular 21+ Signal Forms, use the `[field]` input for direct integration. The datepicker automatically tracks dirty state when using this binding:
66
+
67
+ ```typescript
68
+ import { Component, signal, form, objectSchema } from '@angular/core';
69
+ import { NgxsmkDatepickerComponent } from 'ngxsmk-datepicker';
70
+
71
+ @Component({
72
+ selector: 'app-form',
73
+ standalone: true,
74
+ imports: [NgxsmkDatepickerComponent],
75
+ template: `
76
+ <form>
77
+ <ngxsmk-datepicker
78
+ [field]="myForm.dateInQuestion"
79
+ mode="single"
80
+ placeholder="Select a date">
81
+ </ngxsmk-datepicker>
82
+
83
+ <button [disabled]="!myForm().dirty()">Save</button>
84
+ </form>
85
+ `
86
+ })
87
+ export class FormComponent {
88
+ localObject = signal({
89
+ dateInQuestion: new Date()
90
+ });
91
+
92
+ myForm = form(this.localObject, objectSchema({
93
+ dateInQuestion: objectSchema<Date>()
94
+ }));
95
+ }
96
+ ```
97
+
98
+ **Important**: The `[field]` binding automatically tracks dirty state. Avoid mixing it with manual `(valueChange)` handlers that bypass the form API, as this may prevent proper dirty tracking. See the [Signal Forms Integration Guide](signal-forms.md) for detailed documentation.
99
+
100
+ ### Manual Signal Updates
101
+
102
+ If you need more control, you can manually update signals:
103
+
104
+ ```typescript
105
+ import { Component, signal, effect } from '@angular/core';
106
+
107
+ @Component({
108
+ // ...
109
+ })
110
+ export class ExampleComponent {
111
+ selectedDate = signal<DatepickerValue>(null);
112
+
113
+ constructor() {
114
+ // React to date changes
115
+ effect(() => {
116
+ const date = this.selectedDate();
117
+ if (date) {
118
+ console.log('Date changed:', date);
119
+ // Perform side effects like API calls
120
+ }
121
+ });
122
+ }
123
+
124
+ onDateChange(newDate: DatepickerValue) {
125
+ this.selectedDate.set(newDate);
126
+ // Additional logic here
127
+ }
128
+ }
129
+ ```
130
+
131
+ ## httpResource Integration
132
+
133
+ The datepicker works seamlessly with `httpResource` for server-side data:
134
+
135
+ ```typescript
136
+ import { Component, inject } from '@angular/core';
137
+ import { httpResource } from '@angular/common/http';
138
+ import { signal, linkedSignal } from '@angular/core';
139
+
140
+ @Component({
141
+ // ...
142
+ })
143
+ export class DataComponent {
144
+ private http = inject(HttpClient);
145
+
146
+ // Create a resource that fetches data
147
+ resource = httpResource({
148
+ request: () => this.http.get<{ dateInQuestion: Date }>('/api/data'),
149
+ loader: signal(false)
150
+ });
151
+
152
+ // Link the response to a signal
153
+ localObject = linkedSignal(() => this.resource.response.value());
154
+
155
+ // Compute the date from the response
156
+ myDate = computed(() => {
157
+ const obj = this.localObject();
158
+ return obj?.dateInQuestion ? new Date(obj.dateInQuestion) : null;
159
+ });
160
+
161
+ // Update the datepicker when data arrives
162
+ updateDate(newDate: DatepickerValue) {
163
+ // Update your resource or local signal
164
+ this.localObject.update(obj => ({
165
+ ...obj,
166
+ dateInQuestion: newDate
167
+ }));
168
+ }
169
+ }
170
+ ```
171
+
172
+ ```html
173
+ <ngxsmk-datepicker
174
+ [value]="myDate()"
175
+ (valueChange)="updateDate($event)"
176
+ mode="single">
177
+ </ngxsmk-datepicker>
178
+ ```
179
+
180
+ ## Range Selection with Signals
181
+
182
+ For date ranges, use signals with range objects:
183
+
184
+ ```typescript
185
+ import { Component, signal } from '@angular/core';
186
+
187
+ @Component({
188
+ // ...
189
+ })
190
+ export class RangeComponent {
191
+ dateRange = signal<{ start: Date; end: Date } | null>(null);
192
+
193
+ onRangeChange(range: { start: Date; end: Date } | null) {
194
+ this.dateRange.set(range);
195
+ }
196
+ }
197
+ ```
198
+
199
+ ```html
200
+ <ngxsmk-datepicker
201
+ mode="range"
202
+ [value]="dateRange()"
203
+ (valueChange)="dateRange.set($event)">
204
+ </ngxsmk-datepicker>
205
+ ```
206
+
207
+ ## Multiple Date Selection
208
+
209
+ For multiple date selection:
210
+
211
+ ```typescript
212
+ import { Component, signal } from '@angular/core';
213
+
214
+ @Component({
215
+ // ...
216
+ })
217
+ export class MultipleComponent {
218
+ selectedDates = signal<Date[]>([]);
219
+ }
220
+ ```
221
+
222
+ ```html
223
+ <ngxsmk-datepicker
224
+ mode="multiple"
225
+ [value]="selectedDates()"
226
+ (valueChange)="selectedDates.set($event)">
227
+ </ngxsmk-datepicker>
228
+ ```
229
+
230
+ ## Best Practices
231
+
232
+ 1. **Use `signal()` for local state**: For component-local date selection, use writable signals.
233
+
234
+ 2. **Use `[field]` for forms**: When using Angular Signal Forms, prefer the `[field]` input for automatic synchronization and dirty state tracking.
235
+
236
+ 3. **Avoid mixing `[field]` with manual handlers**: Don't use both `[field]` and `(valueChange)` together, as the manual handler may bypass form dirty tracking.
237
+
238
+ 4. **Use `computed()` for derived values**: Derive formatted dates, validation states, or other computed properties.
239
+
240
+ 5. **Handle null values**: Always check for null/undefined when working with datepicker values.
241
+
242
+ 6. **Type safety**: Use the `DatepickerValue` type for better TypeScript support:
243
+ ```typescript
244
+ import { DatepickerValue } from 'ngxsmk-datepicker';
245
+ ```
246
+
247
+ For detailed Signal Forms integration including dirty state tracking, see the [Signal Forms Integration Guide](signal-forms.md).
248
+
249
+ ## Migration from Reactive Forms
250
+
251
+ If you're migrating from Reactive Forms to Signals:
252
+
253
+ **Before (Reactive Forms):**
254
+ ```typescript
255
+ dateControl = new FormControl<DatepickerValue>(null);
256
+ ```
257
+
258
+ **After (Signals):**
259
+ ```typescript
260
+ dateSignal = signal<DatepickerValue>(null);
261
+ ```
262
+
263
+ The datepicker supports both patterns simultaneously, so you can migrate gradually.
264
+
265
+
266
+