@libs-ui/components-datetime-dropdown 0.2.356-8 → 0.2.357-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/README.md +397 -155
- package/directive/date-dropdown.directive.d.ts +2 -2
- package/dropdown.component.d.ts +9 -9
- package/esm2022/defines/date-dropdown.define.mjs +3 -3
- package/esm2022/directive/date-dropdown.directive.mjs +1 -1
- package/esm2022/dropdown.component.mjs +5 -5
- package/esm2022/item/child/child.component.mjs +2 -2
- package/esm2022/item/item.component.mjs +2 -2
- package/fesm2022/libs-ui-components-datetime-dropdown.mjs +8 -8
- package/fesm2022/libs-ui-components-datetime-dropdown.mjs.map +1 -1
- package/item/child/child.component.d.ts +1 -1
- package/package.json +8 -8
package/README.md
CHANGED
|
@@ -1,26 +1,38 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @libs-ui/components-datetime-dropdown
|
|
2
2
|
|
|
3
|
-
> Component chọn ngày
|
|
3
|
+
> Component dropdown chọn ngày tháng theo từng phần (năm, tháng, quý, ngày) với hỗ trợ single/multi mode, validation tự động và responsive layout.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Giới thiệu
|
|
6
6
|
|
|
7
|
-
`
|
|
7
|
+
`LibsUiComponentsDatetimeDropdownComponent` cung cấp giao diện chọn ngày tháng dạng dropdown riêng biệt cho từng đơn vị thời gian (năm, tháng, quý, ngày). Component hỗ trợ 6 định dạng hiển thị khác nhau qua `typeFormat`, chế độ chọn đơn (`single`) và chọn khoảng (`multi` từ/đến) với validation so sánh tự động giữa hai đầu. Layout tự động responsive — tự chuyển sang dạng dọc khi không đủ không gian ngang.
|
|
8
|
+
|
|
9
|
+
## Tính năng
|
|
10
|
+
|
|
11
|
+
- 6 định dạng: `year`, `month`, `quarter`, `year-month`, `month-day`, `year-quarter`
|
|
12
|
+
- Chế độ single (chọn một thời điểm) và multi (chọn khoảng from-to)
|
|
13
|
+
- Validation so sánh tự động: from phải nhỏ hơn to (có thể cấu hình)
|
|
14
|
+
- Validation required với message tùy chỉnh
|
|
15
|
+
- Responsive layout — tự động stack dọc khi không đủ không gian
|
|
16
|
+
- Điều khiển từ bên ngoài qua `FunctionsControl` (checkIsValid, resetError, resetTime)
|
|
17
|
+
- Hỗ trợ disable từng key (năm/tháng/quý/ngày) cho from và to riêng biệt
|
|
18
|
+
- Ẩn các giá trị cụ thể trong dropdown (`hiddenDate`)
|
|
19
|
+
- Tích hợp `ILabel` từ `@libs-ui/components-label`
|
|
8
20
|
|
|
9
21
|
## Khi nào sử dụng
|
|
10
22
|
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
23
|
+
- Khi cần chọn ngày tháng theo từng phần riêng biệt thay vì dùng calendar picker
|
|
24
|
+
- Khi cần chọn khoảng thời gian from-to với validation so sánh tự động
|
|
25
|
+
- Khi cần format hiển thị linh hoạt (`year-month`, `month-day`, `year-quarter`, ...)
|
|
26
|
+
- Khi cần điều khiển validate và reset từ component cha (submit form, reset button)
|
|
27
|
+
- Khi cần responsive layout tự động co giãn theo container
|
|
15
28
|
|
|
16
|
-
##
|
|
29
|
+
## Cài đặt
|
|
17
30
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
- Component tự động responsive khi không đủ không gian
|
|
31
|
+
```bash
|
|
32
|
+
npm install @libs-ui/components-datetime-dropdown
|
|
33
|
+
```
|
|
22
34
|
|
|
23
|
-
##
|
|
35
|
+
## Import
|
|
24
36
|
|
|
25
37
|
```typescript
|
|
26
38
|
import {
|
|
@@ -28,194 +40,373 @@ import {
|
|
|
28
40
|
IEmitSingleDateDropdown,
|
|
29
41
|
IEmitMultiDateDropdown,
|
|
30
42
|
IDateDropdownFunctionControlEvent,
|
|
31
|
-
TYPE_DATE_DROPDOWN_FORMAT,
|
|
32
43
|
IFromAndToDateLabel,
|
|
33
44
|
IValidDateDropdown,
|
|
45
|
+
IDateDropdownDisableKeys,
|
|
46
|
+
IDateDropdownDisable,
|
|
47
|
+
IHiddenDate,
|
|
48
|
+
TYPE_DATE_DROPDOWN_FORMAT,
|
|
49
|
+
TYPE_DATE_FORMAT,
|
|
34
50
|
} from '@libs-ui/components-datetime-dropdown';
|
|
35
51
|
```
|
|
36
52
|
|
|
37
53
|
## Ví dụ sử dụng
|
|
38
54
|
|
|
39
|
-
### 1.
|
|
40
|
-
|
|
41
|
-
```html
|
|
42
|
-
<libs_ui-components-datetime-dropdown
|
|
43
|
-
[typeFormat]="'month-day'"
|
|
44
|
-
(outChooseSingleDate)="onSingleDateSelected($event)"
|
|
45
|
-
></libs_ui-components-datetime-dropdown>
|
|
46
|
-
```
|
|
55
|
+
### 1. Single mode — chọn tháng và ngày (mặc định)
|
|
47
56
|
|
|
48
57
|
```typescript
|
|
49
|
-
|
|
50
|
-
import {
|
|
58
|
+
// my-form.component.ts
|
|
59
|
+
import { Component } from '@angular/core';
|
|
60
|
+
import {
|
|
61
|
+
LibsUiComponentsDatetimeDropdownComponent,
|
|
62
|
+
IEmitSingleDateDropdown,
|
|
63
|
+
IDateDropdownFunctionControlEvent,
|
|
64
|
+
} from '@libs-ui/components-datetime-dropdown';
|
|
65
|
+
|
|
66
|
+
@Component({
|
|
67
|
+
selector: 'app-my-form',
|
|
68
|
+
standalone: true,
|
|
69
|
+
imports: [LibsUiComponentsDatetimeDropdownComponent],
|
|
70
|
+
templateUrl: './my-form.component.html',
|
|
71
|
+
})
|
|
72
|
+
export class MyFormComponent {
|
|
73
|
+
private dropdownControl?: IDateDropdownFunctionControlEvent;
|
|
74
|
+
|
|
75
|
+
handlerFunctionsControl(event: IDateDropdownFunctionControlEvent): void {
|
|
76
|
+
event.stopPropagation();
|
|
77
|
+
this.dropdownControl = event;
|
|
78
|
+
}
|
|
51
79
|
|
|
52
|
-
|
|
53
|
-
|
|
80
|
+
handlerSingleDateSelected(event: IEmitSingleDateDropdown): void {
|
|
81
|
+
event.stopPropagation();
|
|
82
|
+
console.log('Tháng:', event.month, 'Ngày:', event.day);
|
|
83
|
+
}
|
|
54
84
|
}
|
|
55
85
|
```
|
|
56
86
|
|
|
57
|
-
|
|
87
|
+
```html
|
|
88
|
+
<!-- my-form.component.html -->
|
|
89
|
+
<libs_ui-components-datetime-dropdown
|
|
90
|
+
[typeFormat]="'month-day'"
|
|
91
|
+
(outChooseSingleDate)="handlerSingleDateSelected($event)"
|
|
92
|
+
(outFunctionsControl)="handlerFunctionsControl($event)"
|
|
93
|
+
/>
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### 2. Các định dạng khác nhau
|
|
58
97
|
|
|
59
98
|
```html
|
|
60
|
-
<!-- Chỉ
|
|
99
|
+
<!-- Chỉ năm — đảo ngược, giới hạn từ 2020 đến 2030 -->
|
|
61
100
|
<libs_ui-components-datetime-dropdown
|
|
62
101
|
[typeFormat]="'year'"
|
|
63
102
|
[reverseYear]="true"
|
|
64
103
|
[minYear]="2020"
|
|
65
104
|
[maxYear]="2030"
|
|
66
|
-
(outChooseSingleDate)="
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
<!-- Chỉ chọn tháng -->
|
|
70
|
-
<libs_ui-components-datetime-dropdown
|
|
71
|
-
[typeFormat]="'month'"
|
|
72
|
-
(outChooseSingleDate)="onMonthSelected($event)"
|
|
73
|
-
></libs_ui-components-datetime-dropdown>
|
|
105
|
+
(outChooseSingleDate)="handlerYearSelected($event)"
|
|
106
|
+
/>
|
|
74
107
|
|
|
75
|
-
<!--
|
|
108
|
+
<!-- Năm - tháng -->
|
|
76
109
|
<libs_ui-components-datetime-dropdown
|
|
77
110
|
[typeFormat]="'year-month'"
|
|
78
|
-
(outChooseSingleDate)="
|
|
79
|
-
|
|
111
|
+
(outChooseSingleDate)="handlerYearMonthSelected($event)"
|
|
112
|
+
/>
|
|
80
113
|
|
|
81
|
-
<!--
|
|
114
|
+
<!-- Năm - quý -->
|
|
82
115
|
<libs_ui-components-datetime-dropdown
|
|
83
116
|
[typeFormat]="'year-quarter'"
|
|
84
|
-
(outChooseSingleDate)="
|
|
85
|
-
|
|
117
|
+
(outChooseSingleDate)="handlerYearQuarterSelected($event)"
|
|
118
|
+
/>
|
|
119
|
+
|
|
120
|
+
<!-- Chỉ quý -->
|
|
121
|
+
<libs_ui-components-datetime-dropdown
|
|
122
|
+
[typeFormat]="'quarter'"
|
|
123
|
+
(outChooseSingleDate)="handlerQuarterSelected($event)"
|
|
124
|
+
/>
|
|
86
125
|
```
|
|
87
126
|
|
|
88
|
-
|
|
127
|
+
```typescript
|
|
128
|
+
handlerYearSelected(event: IEmitSingleDateDropdown): void {
|
|
129
|
+
event.stopPropagation();
|
|
130
|
+
console.log('Năm:', event.year);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
handlerYearMonthSelected(event: IEmitSingleDateDropdown): void {
|
|
134
|
+
event.stopPropagation();
|
|
135
|
+
console.log('Năm:', event.year, 'Tháng:', event.month);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
handlerYearQuarterSelected(event: IEmitSingleDateDropdown): void {
|
|
139
|
+
event.stopPropagation();
|
|
140
|
+
console.log('Năm:', event.year, 'Quý:', event.quarter);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
handlerQuarterSelected(event: IEmitSingleDateDropdown): void {
|
|
144
|
+
event.stopPropagation();
|
|
145
|
+
console.log('Quý:', event.quarter);
|
|
146
|
+
}
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### 3. Multi mode — chọn khoảng thời gian from-to
|
|
150
|
+
|
|
151
|
+
```typescript
|
|
152
|
+
// date-range-filter.component.ts
|
|
153
|
+
import { Component, signal } from '@angular/core';
|
|
154
|
+
import {
|
|
155
|
+
LibsUiComponentsDatetimeDropdownComponent,
|
|
156
|
+
IEmitMultiDateDropdown,
|
|
157
|
+
IEmitSingleDateDropdown,
|
|
158
|
+
IDateDropdownFunctionControlEvent,
|
|
159
|
+
} from '@libs-ui/components-datetime-dropdown';
|
|
160
|
+
|
|
161
|
+
@Component({
|
|
162
|
+
selector: 'app-date-range-filter',
|
|
163
|
+
standalone: true,
|
|
164
|
+
imports: [LibsUiComponentsDatetimeDropdownComponent],
|
|
165
|
+
templateUrl: './date-range-filter.component.html',
|
|
166
|
+
})
|
|
167
|
+
export class DateRangeFilterComponent {
|
|
168
|
+
private dropdownControl?: IDateDropdownFunctionControlEvent;
|
|
169
|
+
|
|
170
|
+
// Giá trị khởi tạo ban đầu (từ tháng 1 đến tháng 6 năm 2024)
|
|
171
|
+
readonly selectedRange: IEmitMultiDateDropdown = {
|
|
172
|
+
from: signal<IEmitSingleDateDropdown>({ year: 2024, month: 1 }),
|
|
173
|
+
to: signal<IEmitSingleDateDropdown>({ year: 2024, month: 6 }),
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
handlerFunctionsControl(event: IDateDropdownFunctionControlEvent): void {
|
|
177
|
+
event.stopPropagation();
|
|
178
|
+
this.dropdownControl = event;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
handlerMultiDateSelected(event: IEmitMultiDateDropdown): void {
|
|
182
|
+
event.stopPropagation();
|
|
183
|
+
console.log('Từ:', event.from());
|
|
184
|
+
console.log('Đến:', event.to());
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
async handlerSubmit(): Promise<void> {
|
|
188
|
+
const isValid = await this.dropdownControl?.checkIsValid();
|
|
189
|
+
if (!isValid) {
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
// Tiến hành submit
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
async handlerReset(): Promise<void> {
|
|
196
|
+
await this.dropdownControl?.resetTime?.();
|
|
197
|
+
await this.dropdownControl?.resetError?.();
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
```
|
|
89
201
|
|
|
90
202
|
```html
|
|
203
|
+
<!-- date-range-filter.component.html -->
|
|
91
204
|
<libs_ui-components-datetime-dropdown
|
|
92
205
|
[typeFormat]="'year-month'"
|
|
93
206
|
[isMultiple]="true"
|
|
94
|
-
[fromAndToDateLabel]="{ from: 'i18n_label_from', to: 'i18n_to' }"
|
|
95
207
|
[selectedDateTime]="selectedRange"
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
208
|
+
[fromAndToDateLabel]="{ from: 'i18n_label_from', to: 'i18n_to' }"
|
|
209
|
+
[validRequired]="{ message: 'i18n_required', messageValidCompareTime: 'i18n_invalid_end_date_selected' }"
|
|
210
|
+
(outChooseMultiDate)="handlerMultiDateSelected($event)"
|
|
211
|
+
(outFunctionsControl)="handlerFunctionsControl($event)"
|
|
212
|
+
/>
|
|
213
|
+
|
|
214
|
+
<button (click)="handlerSubmit()">Tìm kiếm</button>
|
|
215
|
+
<button (click)="handlerReset()">Xóa bộ lọc</button>
|
|
99
216
|
```
|
|
100
217
|
|
|
218
|
+
### 4. Disable từng key (năm/tháng/quý/ngày) riêng biệt
|
|
219
|
+
|
|
101
220
|
```typescript
|
|
102
|
-
|
|
221
|
+
// filter.component.ts
|
|
222
|
+
import { Component, signal } from '@angular/core';
|
|
103
223
|
import {
|
|
224
|
+
LibsUiComponentsDatetimeDropdownComponent,
|
|
104
225
|
IEmitMultiDateDropdown,
|
|
105
|
-
|
|
106
|
-
IDateDropdownFunctionControlEvent,
|
|
226
|
+
IDateDropdownDisableKeys,
|
|
107
227
|
} from '@libs-ui/components-datetime-dropdown';
|
|
108
228
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
229
|
+
@Component({
|
|
230
|
+
selector: 'app-filter',
|
|
231
|
+
standalone: true,
|
|
232
|
+
imports: [LibsUiComponentsDatetimeDropdownComponent],
|
|
233
|
+
templateUrl: './filter.component.html',
|
|
234
|
+
})
|
|
235
|
+
export class FilterComponent {
|
|
236
|
+
// Disable quý 1 và quý 4 cho phía "from"
|
|
237
|
+
readonly disabledKeys: IDateDropdownDisableKeys = {
|
|
238
|
+
from: signal({
|
|
239
|
+
quarter: signal([1, 4]),
|
|
240
|
+
}),
|
|
241
|
+
to: signal({
|
|
242
|
+
quarter: signal([]),
|
|
243
|
+
}),
|
|
244
|
+
};
|
|
245
|
+
|
|
246
|
+
handlerMultiDateSelected(event: IEmitMultiDateDropdown): void {
|
|
247
|
+
event.stopPropagation();
|
|
248
|
+
console.log('Khoảng:', event.from(), event.to());
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
```
|
|
113
252
|
|
|
114
|
-
|
|
253
|
+
```html
|
|
254
|
+
<!-- filter.component.html -->
|
|
255
|
+
<libs_ui-components-datetime-dropdown
|
|
256
|
+
[typeFormat]="'year-quarter'"
|
|
257
|
+
[isMultiple]="true"
|
|
258
|
+
[listKeysDisable]="disabledKeys"
|
|
259
|
+
(outChooseMultiDate)="handlerMultiDateSelected($event)"
|
|
260
|
+
/>
|
|
261
|
+
```
|
|
115
262
|
|
|
116
|
-
|
|
117
|
-
console.log('From:', event.from(), 'To:', event.to());
|
|
118
|
-
}
|
|
263
|
+
### 5. Với label và emit liên tục mỗi lần chọn
|
|
119
264
|
|
|
120
|
-
|
|
121
|
-
|
|
265
|
+
```typescript
|
|
266
|
+
import { Component, signal } from '@angular/core';
|
|
267
|
+
import {
|
|
268
|
+
LibsUiComponentsDatetimeDropdownComponent,
|
|
269
|
+
IEmitSingleDateDropdown,
|
|
270
|
+
IEmitMultiDateDropdown,
|
|
271
|
+
} from '@libs-ui/components-datetime-dropdown';
|
|
272
|
+
import { ILabel } from '@libs-ui/components-label';
|
|
273
|
+
|
|
274
|
+
@Component({
|
|
275
|
+
selector: 'app-with-label',
|
|
276
|
+
standalone: true,
|
|
277
|
+
imports: [LibsUiComponentsDatetimeDropdownComponent],
|
|
278
|
+
templateUrl: './with-label.component.html',
|
|
279
|
+
})
|
|
280
|
+
export class WithLabelComponent {
|
|
281
|
+
readonly labelConfig: ILabel = {
|
|
282
|
+
labelLeft: 'Kỳ báo cáo',
|
|
283
|
+
required: true,
|
|
284
|
+
};
|
|
285
|
+
|
|
286
|
+
handlerSelectedDropdown(event: IEmitSingleDateDropdown | IEmitMultiDateDropdown): void {
|
|
287
|
+
event.stopPropagation();
|
|
288
|
+
console.log('Giá trị vừa chọn:', event);
|
|
289
|
+
}
|
|
122
290
|
}
|
|
123
291
|
```
|
|
124
292
|
|
|
125
|
-
### 4. With Validation
|
|
126
|
-
|
|
127
293
|
```html
|
|
128
294
|
<libs_ui-components-datetime-dropdown
|
|
129
295
|
[typeFormat]="'year-month'"
|
|
130
|
-
[
|
|
131
|
-
[
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
[isCheckErrorWhenSelectItem]="true"
|
|
135
|
-
[isBorderError]="isBorderError"
|
|
136
|
-
(outFunctionsControl)="onFunctionsControl($event)"
|
|
137
|
-
(outChooseMultiDate)="onMultiDateSelected($event)"
|
|
138
|
-
></libs_ui-components-datetime-dropdown>
|
|
296
|
+
[labelConfig]="labelConfig"
|
|
297
|
+
[isEmitAfterChanged]="true"
|
|
298
|
+
(outSelectedDropdown)="handlerSelectedDropdown($event)"
|
|
299
|
+
/>
|
|
139
300
|
```
|
|
140
301
|
|
|
302
|
+
## @Input()
|
|
303
|
+
|
|
304
|
+
| Input | Type | Default | Mô tả | Ví dụ |
|
|
305
|
+
|---|---|---|---|---|
|
|
306
|
+
| `[classIncludeTextDisplayWhenNoSelect]` | `string \| undefined` | `undefined` | CSS class tùy chỉnh cho text hiển thị khi chưa chọn giá trị | `[classIncludeTextDisplayWhenNoSelect]="'text-gray-400'"` |
|
|
307
|
+
| `[disable]` | `boolean` | `false` | Vô hiệu hóa toàn bộ component | `[disable]="true"` |
|
|
308
|
+
| `[disableSecond]` | `boolean` | `false` | Vô hiệu hóa dropdown thứ hai cho đến khi dropdown đầu tiên được chọn | `[disableSecond]="true"` |
|
|
309
|
+
| `[fromAndToDateLabel]` | `IFromAndToDateLabel` | `{ from: 'i18n_label_from', to: 'i18n_to' }` | Tùy chỉnh label From/To và CSS class của chúng khi `isMultiple=true` | `[fromAndToDateLabel]="{ from: 'Từ', to: 'Đến' }"` |
|
|
310
|
+
| `[getItemYearDisplay]` | `(year: string) => string` | `undefined` | Hàm tùy chỉnh cách hiển thị label năm trong dropdown | `[getItemYearDisplay]="formatYear"` |
|
|
311
|
+
| `[hiddenDate]` | `IHiddenDate \| undefined` | `undefined` | Ẩn các giá trị ngày/tháng cụ thể khỏi danh sách dropdown | `[hiddenDate]="hiddenConfig"` |
|
|
312
|
+
| `[ignoreAllowTimeEqual]` | `boolean` | `true` | Khi `true`: from phải nhỏ hơn to (không cho bằng nhau). Khi `false`: from có thể bằng to | `[ignoreAllowTimeEqual]="false"` |
|
|
313
|
+
| `[ignoreConvertYearSelected]` | `boolean` | `false` | Hiển thị giá trị năm gốc thay vì qua i18n convert | `[ignoreConvertYearSelected]="true"` |
|
|
314
|
+
| `[ignoreFromAndToDateLabel]` | `boolean` | `false` | Ẩn label From/To, chỉ hiển thị dấu `-` ngăn cách | `[ignoreFromAndToDateLabel]="true"` |
|
|
315
|
+
| `[ignoreRequiredValueSecondWhenNotValidRequired]` | `boolean` | `false` | Bỏ qua validate giá trị thứ hai khi `validRequired` không được cấu hình | `[ignoreRequiredValueSecondWhenNotValidRequired]="true"` |
|
|
316
|
+
| `[ignoreValidTimeCompare]` | `boolean` | `false` | Bỏ qua validation so sánh từ/đến (hữu ích khi chỉ cần validate required) | `[ignoreValidTimeCompare]="true"` |
|
|
317
|
+
| `[isBorderError]` | `boolean` | `false` | Hiển thị viền đỏ lỗi trên tất cả dropdown | `[isBorderError]="hasError"` |
|
|
318
|
+
| `[isCheckErrorWhenSelectItem]` | `boolean` | `true` | Tự động kiểm tra và hiển thị lỗi mỗi khi người dùng chọn một item | `[isCheckErrorWhenSelectItem]="false"` |
|
|
319
|
+
| `[isEmitAfterChanged]` | `boolean` | `false` | Emit `outSelectedDropdown` mỗi lần chọn giá trị (kể cả khi chưa chọn đủ). Cần check `undefined` cẩn thận | `[isEmitAfterChanged]="true"` |
|
|
320
|
+
| `[isMultiple]` | `boolean` | `false` | Bật chế độ chọn khoảng thời gian — hiển thị hai nhóm dropdown (From/To) với validation so sánh | `[isMultiple]="true"` |
|
|
321
|
+
| `[labelConfig]` | `ILabel \| undefined` | `undefined` | Cấu hình label phía trên component, dùng `ILabel` từ `@libs-ui/components-label` | `[labelConfig]="{ labelLeft: 'Kỳ báo cáo', required: true }"` |
|
|
322
|
+
| `[listHasButtonUnSelectOption]` | `boolean` | `false` | Hiển thị nút "Bỏ chọn" trong danh sách dropdown | `[listHasButtonUnSelectOption]="true"` |
|
|
323
|
+
| `[listKeysDisable]` | `IDateDropdownDisableKeys \| undefined` | `undefined` | Cấu hình disable từng giá trị (năm/tháng/quý/ngày) cho from và to riêng biệt | `[listKeysDisable]="disabledKeys"` |
|
|
324
|
+
| `[listMaxItemShow]` | `{ year?: number; month?: number; quarter?: number; day?: number } \| undefined` | `undefined` | Giới hạn số lượng item tối đa hiển thị trong dropdown cho từng loại | `[listMaxItemShow]="{ year: 5 }"` |
|
|
325
|
+
| `[maxYear]` | `number` | `0` (dùng DEFAULT_MAX_YEAR từ picker) | Năm tối đa hiển thị trong dropdown năm | `[maxYear]="2030"` |
|
|
326
|
+
| `[minWidth]` | `number \| undefined` | `undefined` | Chiều rộng tối thiểu của toàn bộ component (px) | `[minWidth]="200"` |
|
|
327
|
+
| `[minYear]` | `number` | `0` (dùng DEFAULT_MIN_YEAR từ picker) | Năm tối thiểu hiển thị trong dropdown năm | `[minYear]="2020"` |
|
|
328
|
+
| `[readonly]` | `boolean` | `false` | Chế độ chỉ đọc — hiển thị giá trị nhưng không cho phép thay đổi | `[readonly]="true"` |
|
|
329
|
+
| `[reverseYear]` | `boolean \| undefined` | `undefined` | Đảo ngược thứ tự danh sách năm (năm mới nhất hiển thị trên đầu) | `[reverseYear]="true"` |
|
|
330
|
+
| `[selectedDateTime]` | `IEmitMultiDateDropdown \| undefined` | `undefined` | Giá trị khởi tạo — phải dùng `WritableSignal` bên trong (xem interface `IEmitMultiDateDropdown`) | `[selectedDateTime]="selectedRange"` |
|
|
331
|
+
| `[typeFormat]` | `TYPE_DATE_DROPDOWN_FORMAT` | `'month-day'` | Định dạng dropdown hiển thị: `'year'`, `'month'`, `'quarter'`, `'year-month'`, `'month-day'`, `'year-quarter'` | `[typeFormat]="'year-month'"` |
|
|
332
|
+
| `[validRequired]` | `IValidDateDropdown \| undefined` | `undefined` | Cấu hình validation bắt buộc với message lỗi tùy chỉnh | `[validRequired]="{ message: 'i18n_required' }"` |
|
|
333
|
+
| `[widthByElement]` | `boolean` | `false` | Tự động tính chiều rộng dropdown theo kích thước phần tử cha | `[widthByElement]="true"` |
|
|
334
|
+
| `[widthDropdown]` | `number` | `136` | Chiều rộng (px) của mỗi ô dropdown đơn lẻ | `[widthDropdown]="160"` |
|
|
335
|
+
| `[zIndex]` | `number` | `1200` | z-index của dropdown overlay khi mở | `[zIndex]="1300"` |
|
|
336
|
+
|
|
337
|
+
## @Output()
|
|
338
|
+
|
|
339
|
+
| Output | Type | Mô tả | Handler TS | Binding HTML |
|
|
340
|
+
|---|---|---|---|---|
|
|
341
|
+
| `(outChangStageFlagMouse)` | `IFlagMouse` | Emit khi trạng thái chuột thay đổi (hover/leave trên dropdown) | `handlerFlagMouseChange(event: IFlagMouse): void { event.stopPropagation(); ... }` | `(outChangStageFlagMouse)="handlerFlagMouseChange($event)"` |
|
|
342
|
+
| `(outChooseMultiDate)` | `IEmitMultiDateDropdown` | Emit khi người dùng chọn đầy đủ cả From và To (chỉ khi `isMultiple=true`). Chỉ emit khi cả hai hợp lệ | `handlerMultiDateSelected(event: IEmitMultiDateDropdown): void { event.stopPropagation(); ... }` | `(outChooseMultiDate)="handlerMultiDateSelected($event)"` |
|
|
343
|
+
| `(outChooseSingleDate)` | `IEmitSingleDateDropdown` | Emit khi người dùng chọn đầy đủ tất cả các trường theo `typeFormat` (chỉ khi `isMultiple=false`) | `handlerSingleDateSelected(event: IEmitSingleDateDropdown): void { event.stopPropagation(); ... }` | `(outChooseSingleDate)="handlerSingleDateSelected($event)"` |
|
|
344
|
+
| `(outFunctionsControl)` | `IDateDropdownFunctionControlEvent` | Emit object chứa các hàm điều khiển component từ bên ngoài. Được emit một lần trong `ngOnInit` | `handlerFunctionsControl(event: IDateDropdownFunctionControlEvent): void { event.stopPropagation(); this.ctrl = event; }` | `(outFunctionsControl)="handlerFunctionsControl($event)"` |
|
|
345
|
+
| `(outSelectedDropdown)` | `IEmitSingleDateDropdown \| IEmitMultiDateDropdown` | Emit mỗi khi người dùng chọn bất kỳ giá trị nào. Chỉ hoạt động khi `isEmitAfterChanged=true`. Lưu ý: cần kiểm tra `undefined` kỹ khi sử dụng | `handlerSelectedDropdown(event: IEmitSingleDateDropdown \| IEmitMultiDateDropdown): void { event.stopPropagation(); ... }` | `(outSelectedDropdown)="handlerSelectedDropdown($event)"` |
|
|
346
|
+
|
|
347
|
+
## FunctionsControl (IDateDropdownFunctionControlEvent)
|
|
348
|
+
|
|
349
|
+
Nhận qua `(outFunctionsControl)`, dùng để điều khiển component từ bên ngoài (thường là từ nút Submit/Reset của form).
|
|
350
|
+
|
|
351
|
+
| Method | Signature | Mô tả |
|
|
352
|
+
|---|---|---|
|
|
353
|
+
| `checkIsValid()` | `() => Promise<boolean>` | Kiểm tra toàn bộ validation (required + so sánh from/to). Trả về `false` nếu có lỗi và hiển thị trạng thái lỗi trên UI |
|
|
354
|
+
| `resetError()` | `() => Promise<void>` | Xóa tất cả trạng thái lỗi đang hiển thị trên component |
|
|
355
|
+
| `resetTime()` | `() => Promise<void>` | Reset toàn bộ giá trị đã chọn về trạng thái trống |
|
|
356
|
+
|
|
141
357
|
```typescript
|
|
142
|
-
|
|
143
|
-
|
|
358
|
+
// Sử dụng FunctionsControl trong form submit
|
|
359
|
+
private dropdownControl?: IDateDropdownFunctionControlEvent;
|
|
360
|
+
|
|
361
|
+
handlerFunctionsControl(event: IDateDropdownFunctionControlEvent): void {
|
|
362
|
+
event.stopPropagation();
|
|
363
|
+
this.dropdownControl = event;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
async handlerSubmit(): Promise<void> {
|
|
367
|
+
const isValid = await this.dropdownControl?.checkIsValid();
|
|
144
368
|
if (!isValid) {
|
|
145
|
-
return;
|
|
369
|
+
return; // dừng lại nếu có lỗi
|
|
146
370
|
}
|
|
147
|
-
//
|
|
371
|
+
// tiến hành submit
|
|
148
372
|
}
|
|
149
373
|
|
|
150
|
-
|
|
151
|
-
this.
|
|
152
|
-
this.
|
|
374
|
+
async handlerReset(): Promise<void> {
|
|
375
|
+
await this.dropdownControl?.resetTime?.();
|
|
376
|
+
await this.dropdownControl?.resetError?.();
|
|
153
377
|
}
|
|
154
378
|
```
|
|
155
379
|
|
|
156
|
-
## API Reference
|
|
157
|
-
|
|
158
|
-
### Inputs
|
|
159
|
-
|
|
160
|
-
| Tên | Kiểu | Mặc định | Mô tả |
|
|
161
|
-
| --- | --- | --- | --- |
|
|
162
|
-
| `[classIncludeTextDisplayWhenNoSelect]` | `string \| undefined` | `undefined` | CSS class tùy chỉnh text hiển thị khi chưa chọn giá trị |
|
|
163
|
-
| `[disable]` | `boolean` | `false` | Vô hiệu hóa toàn bộ component |
|
|
164
|
-
| `[disableSecond]` | `boolean` | `false` | Vô hiệu hóa dropdown thứ hai cho đến khi dropdown đầu tiên được chọn |
|
|
165
|
-
| `[fromAndToDateLabel]` | `IFromAndToDateLabel` | `{ from: 'i18n_label_from', to: 'i18n_to' }` | Tùy chỉnh label From/To khi `isMultiple=true` |
|
|
166
|
-
| `[getItemYearDisplay]` | `(year: string) => string` | — | Hàm tùy chỉnh hiển thị label cho item năm |
|
|
167
|
-
| `[hiddenDate]` | `IHiddenDate \| undefined` | `undefined` | Ẩn các giá trị ngày/tháng cụ thể khỏi dropdown |
|
|
168
|
-
| `[ignoreAllowTimeEqual]` | `boolean` | `true` | Bỏ qua cho phép thời gian bằng nhau khi so sánh from/to. `true` = from phải nhỏ hơn to (không cho bằng) |
|
|
169
|
-
| `[ignoreConvertYearSelected]` | `boolean` | `false` | Bỏ qua chuyển đổi label năm đã chọn (hiển thị raw value) |
|
|
170
|
-
| `[ignoreFromAndToDateLabel]` | `boolean` | `false` | Ẩn label From/To khi `isMultiple=true` |
|
|
171
|
-
| `[ignoreRequiredValueSecondWhenNotValidRequired]` | `boolean` | `false` | Bỏ qua validate giá trị thứ 2 khi `validRequired` không được set |
|
|
172
|
-
| `[ignoreValidTimeCompare]` | `boolean` | `false` | Bỏ qua validation so sánh thời gian from/to |
|
|
173
|
-
| `[isBorderError]` | `boolean` | `false` | Hiển thị viền lỗi trên component |
|
|
174
|
-
| `[isCheckErrorWhenSelectItem]` | `boolean` | `true` | Kiểm tra lỗi mỗi khi chọn item |
|
|
175
|
-
| `[isEmitAfterChanged]` | `boolean` | `false` | Emit `outSelectedDropdown` mỗi lần chọn giá trị (bao gồm lần đầu init) |
|
|
176
|
-
| `[isMultiple]` | `boolean` | `false` | Chế độ multi selection (From/To) — hiển thị 2 nhóm dropdown |
|
|
177
|
-
| `[labelConfig]` | `ILabel \| undefined` | `undefined` | Cấu hình label (từ `@libs-ui/components-label`) |
|
|
178
|
-
| `[listHasButtonUnSelectOption]` | `boolean` | `false` | Hiển thị nút bỏ chọn trong dropdown list |
|
|
179
|
-
| `[listKeysDisable]` | `IDateDropdownDisableKeys \| undefined` | `undefined` | Danh sách key bị vô hiệu hóa cho từng dropdown (from/to) |
|
|
180
|
-
| `[listMaxItemShow]` | `{ year?: number; month?: number; quarter?: number; day?: number } \| undefined` | `undefined` | Giới hạn số item hiển thị cho từng loại dropdown |
|
|
181
|
-
| `[maxYear]` | `number` | `0` (sử dụng DEFAULT_MAX_YEAR) | Năm tối đa hiển thị trong dropdown năm |
|
|
182
|
-
| `[minWidth]` | `number \| undefined` | `undefined` | Chiều rộng tối thiểu của component (px) |
|
|
183
|
-
| `[minYear]` | `number` | `0` (sử dụng DEFAULT_MIN_YEAR) | Năm tối thiểu hiển thị trong dropdown năm |
|
|
184
|
-
| `[readonly]` | `boolean` | `false` | Chế độ chỉ đọc |
|
|
185
|
-
| `[reverseYear]` | `boolean \| undefined` | `undefined` | Đảo ngược thứ tự danh sách năm (năm mới nhất lên đầu) |
|
|
186
|
-
| `[selectedDateTime]` | `IEmitMultiDateDropdown \| undefined` | `undefined` | Giá trị khởi tạo — sử dụng `WritableSignal` bên trong |
|
|
187
|
-
| `[typeFormat]` | `TYPE_DATE_DROPDOWN_FORMAT` | `'month-day'` | Loại format hiển thị: `'year'`, `'month'`, `'quarter'`, `'year-month'`, `'month-day'`, `'year-quarter'` |
|
|
188
|
-
| `[validRequired]` | `IValidDateDropdown` | — | Cấu hình validation bắt buộc với message lỗi tùy chỉnh |
|
|
189
|
-
| `[widthByElement]` | `boolean` | `false` | Tính width dropdown theo phần tử cha |
|
|
190
|
-
| `[widthDropdown]` | `number` | `136` | Chiều rộng mỗi dropdown (px) |
|
|
191
|
-
| `[zIndex]` | `number` | `1200` | z-index của dropdown overlay |
|
|
192
|
-
|
|
193
|
-
### Outputs
|
|
194
|
-
|
|
195
|
-
| Tên | Kiểu | Mô tả |
|
|
196
|
-
| --- | --- | --- |
|
|
197
|
-
| `(outChangStageFlagMouse)` | `EventEmitter<IFlagMouse>` | Emit khi trạng thái chuột thay đổi (hover/leave) |
|
|
198
|
-
| `(outChooseMultiDate)` | `EventEmitter<IEmitMultiDateDropdown>` | Emit khi chọn đầy đủ cả From và To (chỉ khi `isMultiple=true`) |
|
|
199
|
-
| `(outChooseSingleDate)` | `EventEmitter<IEmitSingleDateDropdown>` | Emit khi chọn đầy đủ single date (chỉ khi `isMultiple=false`) |
|
|
200
|
-
| `(outFunctionsControl)` | `EventEmitter<IDateDropdownFunctionControlEvent>` | Emit object chứa các hàm điều khiển component từ bên ngoài |
|
|
201
|
-
| `(outSelectedDropdown)` | `EventEmitter<IEmitSingleDateDropdown \| IEmitMultiDateDropdown>` | Emit mỗi lần chọn giá trị (cần `isEmitAfterChanged=true`). Lưu ý: cần check `undefined` kỹ khi sử dụng |
|
|
202
|
-
|
|
203
|
-
### FunctionsControl Methods
|
|
204
|
-
|
|
205
|
-
Object nhận được từ `(outFunctionsControl)`:
|
|
206
|
-
|
|
207
|
-
| Method | Kiểu trả về | Mô tả |
|
|
208
|
-
| --- | --- | --- |
|
|
209
|
-
| `checkIsValid()` | `Promise<boolean>` | Kiểm tra validation toàn bộ component. Trả về `false` nếu có lỗi required hoặc lỗi so sánh from/to |
|
|
210
|
-
| `resetError()` | `Promise<void>` | Xóa tất cả trạng thái lỗi hiển thị trên component |
|
|
211
|
-
| `resetTime()` | `Promise<void>` | Reset toàn bộ giá trị đã chọn về trạng thái ban đầu |
|
|
212
|
-
|
|
213
380
|
## Types & Interfaces
|
|
214
381
|
|
|
382
|
+
```typescript
|
|
383
|
+
import {
|
|
384
|
+
TYPE_DATE_DROPDOWN_FORMAT,
|
|
385
|
+
TYPE_DATE_FORMAT,
|
|
386
|
+
IEmitSingleDateDropdown,
|
|
387
|
+
IEmitMultiDateDropdown,
|
|
388
|
+
IFromAndToDateLabel,
|
|
389
|
+
IDateDropdownFunctionControlEvent,
|
|
390
|
+
IValidDateDropdown,
|
|
391
|
+
IHiddenDate,
|
|
392
|
+
IDateDropdownDisableKeys,
|
|
393
|
+
IDateDropdownDisable,
|
|
394
|
+
} from '@libs-ui/components-datetime-dropdown';
|
|
395
|
+
```
|
|
396
|
+
|
|
215
397
|
### TYPE_DATE_DROPDOWN_FORMAT
|
|
216
398
|
|
|
399
|
+
Format truyền vào `[typeFormat]` — quyết định dropdown nào xuất hiện:
|
|
400
|
+
|
|
217
401
|
```typescript
|
|
218
|
-
type TYPE_DATE_DROPDOWN_FORMAT =
|
|
402
|
+
type TYPE_DATE_DROPDOWN_FORMAT =
|
|
403
|
+
| 'year' // 1 dropdown: năm
|
|
404
|
+
| 'month' // 1 dropdown: tháng
|
|
405
|
+
| 'quarter' // 1 dropdown: quý
|
|
406
|
+
| 'year-month' // 2 dropdown: năm + tháng
|
|
407
|
+
| 'month-day' // 2 dropdown: tháng + ngày (mặc định)
|
|
408
|
+
| 'year-quarter' // 2 dropdown: năm + quý
|
|
409
|
+
| string; // custom format (ít dùng)
|
|
219
410
|
```
|
|
220
411
|
|
|
221
412
|
### TYPE_DATE_FORMAT
|
|
@@ -226,6 +417,8 @@ type TYPE_DATE_FORMAT = 'year' | 'month' | 'quarter' | 'day';
|
|
|
226
417
|
|
|
227
418
|
### IEmitSingleDateDropdown
|
|
228
419
|
|
|
420
|
+
Dữ liệu emit khi chọn single date (qua `outChooseSingleDate`). Chỉ có các trường tương ứng với `typeFormat`:
|
|
421
|
+
|
|
229
422
|
```typescript
|
|
230
423
|
interface IEmitSingleDateDropdown {
|
|
231
424
|
year?: number;
|
|
@@ -233,15 +426,32 @@ interface IEmitSingleDateDropdown {
|
|
|
233
426
|
quarter?: number;
|
|
234
427
|
day?: number;
|
|
235
428
|
}
|
|
429
|
+
|
|
430
|
+
// Ví dụ: typeFormat="year-month" → { year: 2024, month: 6 }
|
|
431
|
+
// Ví dụ: typeFormat="month-day" → { month: 3, day: 15 }
|
|
432
|
+
// Ví dụ: typeFormat="year" → { year: 2024 }
|
|
236
433
|
```
|
|
237
434
|
|
|
238
435
|
### IEmitMultiDateDropdown
|
|
239
436
|
|
|
437
|
+
Dữ liệu khởi tạo (`selectedDateTime`) và emit khi chọn multi date (`outChooseMultiDate`). Dùng `WritableSignal`:
|
|
438
|
+
|
|
240
439
|
```typescript
|
|
241
440
|
interface IEmitMultiDateDropdown {
|
|
242
441
|
from: WritableSignal<IEmitSingleDateDropdown>;
|
|
243
442
|
to: WritableSignal<IEmitSingleDateDropdown>;
|
|
244
443
|
}
|
|
444
|
+
|
|
445
|
+
// Tạo giá trị khởi tạo:
|
|
446
|
+
import { signal } from '@angular/core';
|
|
447
|
+
const selectedRange: IEmitMultiDateDropdown = {
|
|
448
|
+
from: signal<IEmitSingleDateDropdown>({ year: 2024, month: 1 }),
|
|
449
|
+
to: signal<IEmitSingleDateDropdown>({ year: 2024, month: 12 }),
|
|
450
|
+
};
|
|
451
|
+
|
|
452
|
+
// Đọc giá trị:
|
|
453
|
+
console.log(event.from()); // { year: 2024, month: 1 }
|
|
454
|
+
console.log(event.to()); // { year: 2024, month: 12 }
|
|
245
455
|
```
|
|
246
456
|
|
|
247
457
|
### IDateDropdownFunctionControlEvent
|
|
@@ -256,28 +466,38 @@ interface IDateDropdownFunctionControlEvent {
|
|
|
256
466
|
|
|
257
467
|
### IValidDateDropdown
|
|
258
468
|
|
|
469
|
+
Cấu hình message lỗi cho validation. Dùng với i18n key:
|
|
470
|
+
|
|
259
471
|
```typescript
|
|
260
472
|
interface IValidDateDropdown {
|
|
261
|
-
message?: string;
|
|
262
|
-
interpolateParams?: { any: object };
|
|
263
|
-
messageValidCompareTime?: string;
|
|
264
|
-
interpolateParamsCompareTime?: { any: object };
|
|
473
|
+
message?: string; // i18n key cho lỗi required
|
|
474
|
+
interpolateParams?: { any: object }; // params cho message
|
|
475
|
+
messageValidCompareTime?: string; // i18n key cho lỗi so sánh from > to
|
|
476
|
+
interpolateParamsCompareTime?: { any: object }; // params cho messageValidCompareTime
|
|
265
477
|
}
|
|
478
|
+
|
|
479
|
+
// Ví dụ:
|
|
480
|
+
const validRequired: IValidDateDropdown = {
|
|
481
|
+
message: 'i18n_required',
|
|
482
|
+
messageValidCompareTime: 'i18n_invalid_end_date_selected',
|
|
483
|
+
};
|
|
266
484
|
```
|
|
267
485
|
|
|
268
486
|
### IFromAndToDateLabel
|
|
269
487
|
|
|
270
488
|
```typescript
|
|
271
489
|
interface IFromAndToDateLabel {
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
490
|
+
from?: string; // i18n key hoặc text trực tiếp cho label "From"
|
|
491
|
+
to?: string; // i18n key hoặc text trực tiếp cho label "To"
|
|
492
|
+
classLabelFrom?: string; // CSS class tùy chỉnh cho label "From"
|
|
493
|
+
classLabelTo?: string; // CSS class tùy chỉnh cho label "To"
|
|
276
494
|
}
|
|
277
495
|
```
|
|
278
496
|
|
|
279
497
|
### IDateDropdownDisableKeys
|
|
280
498
|
|
|
499
|
+
Cấu hình disable từng giá trị cho from và to riêng biệt:
|
|
500
|
+
|
|
281
501
|
```typescript
|
|
282
502
|
interface IDateDropdownDisableKeys {
|
|
283
503
|
from?: WritableSignal<IDateDropdownDisable>;
|
|
@@ -290,30 +510,52 @@ interface IDateDropdownDisable {
|
|
|
290
510
|
quarter?: WritableSignal<Array<number>>;
|
|
291
511
|
day?: WritableSignal<Array<number>>;
|
|
292
512
|
}
|
|
513
|
+
|
|
514
|
+
// Ví dụ: disable tháng 1 và tháng 2 cho "from"
|
|
515
|
+
import { signal } from '@angular/core';
|
|
516
|
+
const disabledKeys: IDateDropdownDisableKeys = {
|
|
517
|
+
from: signal({
|
|
518
|
+
month: signal([1, 2]),
|
|
519
|
+
}),
|
|
520
|
+
};
|
|
293
521
|
```
|
|
294
522
|
|
|
295
523
|
### IHiddenDate
|
|
296
524
|
|
|
525
|
+
Ẩn hoàn toàn các giá trị cụ thể khỏi danh sách dropdown:
|
|
526
|
+
|
|
297
527
|
```typescript
|
|
298
528
|
interface IHiddenDate {
|
|
299
529
|
formatDate: TYPE_DATE_DROPDOWN_FORMAT;
|
|
300
|
-
yearMonth?: WritableSignal<Array<WritableSignal<{
|
|
301
|
-
|
|
530
|
+
yearMonth?: WritableSignal<Array<WritableSignal<{
|
|
531
|
+
hiddenYear: number;
|
|
532
|
+
hiddenMonths: Array<number>;
|
|
533
|
+
}>>>;
|
|
534
|
+
monthDay?: WritableSignal<Array<WritableSignal<{
|
|
535
|
+
hiddenMonth: number;
|
|
536
|
+
hiddenDays: Array<number>;
|
|
537
|
+
}>>>;
|
|
302
538
|
}
|
|
303
539
|
```
|
|
304
540
|
|
|
305
|
-
##
|
|
541
|
+
## Lưu ý quan trọng
|
|
306
542
|
|
|
307
|
-
|
|
308
|
-
- Sử dụng `[widthDropdown]` để điều chỉnh chiều rộng mỗi dropdown (mặc định `136px`)
|
|
309
|
-
- Sử dụng `[fromAndToDateLabel]` để tùy chỉnh label From/To, bao gồm cả CSS class qua `classLabelFrom` và `classLabelTo`
|
|
543
|
+
⚠️ **selectedDateTime dùng WritableSignal**: Input `[selectedDateTime]` nhận `IEmitMultiDateDropdown` trong đó `from` và `to` là `WritableSignal`. Phải khởi tạo đúng: `{ from: signal({ year: 2024 }), to: signal({ year: 2024 }) }`.
|
|
310
544
|
|
|
311
|
-
|
|
545
|
+
⚠️ **typeFormat quyết định số dropdown**: `'year-month'` tạo 2 dropdown (năm + tháng), `'year'` tạo 1 dropdown. Output event chỉ có các trường tương ứng với format đã chọn.
|
|
546
|
+
|
|
547
|
+
⚠️ **outChooseMultiDate chỉ emit khi đầy đủ**: Ở multi mode, `outChooseMultiDate` chỉ emit khi cả from và to đều được chọn đầy đủ. Nếu cần emit từng lần chọn, dùng `[isEmitAfterChanged]="true"` kết hợp `(outSelectedDropdown)`.
|
|
548
|
+
|
|
549
|
+
⚠️ **outSelectedDropdown cần check undefined**: Khi dùng `[isEmitAfterChanged]="true"`, output `(outSelectedDropdown)` có thể emit giá trị chưa đầy đủ. Luôn kiểm tra các trường trước khi sử dụng.
|
|
312
550
|
|
|
313
|
-
|
|
551
|
+
⚠️ **ignoreAllowTimeEqual mặc định true**: Mặc định from phải nhỏ hơn to (không cho bằng nhau). Đặt `[ignoreAllowTimeEqual]="false"` nếu muốn cho phép from = to.
|
|
314
552
|
|
|
315
|
-
|
|
553
|
+
⚠️ **widthDropdown áp dụng cho từng dropdown đơn**: Khi `typeFormat="year-month"` và `widthDropdown=136`, tổng chiều rộng sẽ là khoảng `136 * 2 + spacing`. Dùng `[widthByElement]="true"` để component tự tính theo container cha.
|
|
554
|
+
|
|
555
|
+
## Demo
|
|
316
556
|
|
|
317
557
|
```bash
|
|
318
|
-
npx nx
|
|
558
|
+
npx nx serve core-ui
|
|
319
559
|
```
|
|
560
|
+
|
|
561
|
+
Truy cập: http://localhost:4500/datetime/dropdown
|