@libs-ui/components-inputs-search 0.2.356-41 → 0.2.356-43
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
CHANGED
|
@@ -1,27 +1,36 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @libs-ui/components-inputs-search
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
> Ô nhập liệu tìm kiếm với debounce tự động, hỗ trợ phím Enter, nút xóa nhanh và tùy chỉnh icon linh hoạt.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Giới thiệu
|
|
6
6
|
|
|
7
|
-
-
|
|
8
|
-
- ⚡ **Debounce & Throttle**: Tích hợp sẵn cơ chế debounce cho việc nhập liệu và throttle cho phím Enter.
|
|
9
|
-
- 🧹 **Clearable Support**: Hỗ trợ nút xóa (`hasClearSearch`) xuất hiện khi có nội dung trong ô tìm kiếm.
|
|
10
|
-
- 🎨 **Flexible Styling**: Dễ dàng tùy chỉnh border, background, chiều cao và các class CSS bổ sung.
|
|
11
|
-
- ⌨️ **Keyboard Support**: Hỗ trợ phím Enter để kích hoạt tìm kiếm ngay lập tức.
|
|
12
|
-
- 🛡️ **Signal Based**: Hoạt động mượt mà với Angular Signals.
|
|
7
|
+
`@libs-ui/components-inputs-search` là component ô tìm kiếm được xây dựng trên nền `@libs-ui/components-inputs-input`, bổ sung cơ chế debounce tự động để giảm số lần gọi API khi người dùng đang gõ. Component hỗ trợ phím Enter để kích hoạt tìm kiếm ngay lập tức (với throttle chống spam), nút xóa nội dung nhanh khi bật `hasClearSearch`, và đầy đủ các tuỳ chỉnh về icon, border, background thông qua `searchConfig`.
|
|
13
8
|
|
|
14
|
-
##
|
|
9
|
+
## Tính năng
|
|
10
|
+
|
|
11
|
+
- Tự động emit `outSearch` sau khoảng thời gian debounce (mặc định 1000ms) khi người dùng ngừng gõ
|
|
12
|
+
- Emit `outSearch` ngay lập tức khi nhấn Enter (throttle cùng debounce time để chống spam)
|
|
13
|
+
- Nút xóa nội dung nhanh (`hasClearSearch: true`) xuất hiện khi ô có nội dung
|
|
14
|
+
- Emit `outValueChange` mỗi lần gõ phím để lắng nghe thay đổi tức thời
|
|
15
|
+
- Tùy chỉnh icon trái/phải, placeholder, border, background, chiều cao qua `searchConfig`
|
|
16
|
+
- Hỗ trợ `disable`, `readonly`, `ignoreAutoComplete`
|
|
17
|
+
- Cung cấp `outFunctionsControl` để điều khiển programmatically (focus, blur, reset)
|
|
18
|
+
- Hoạt động với Angular Signals và `ChangeDetectionStrategy.OnPush`
|
|
19
|
+
|
|
20
|
+
## Khi nào sử dụng
|
|
15
21
|
|
|
16
|
-
|
|
22
|
+
- Khi cần ô tìm kiếm tự động gửi yêu cầu sau khi người dùng ngừng gõ (debounce) thay vì gửi mỗi keystroke
|
|
23
|
+
- Khi cần tích hợp tìm kiếm vào thanh lọc dữ liệu, bảng danh sách hoặc dropdown autocomplete
|
|
24
|
+
- Khi cần ô tìm kiếm có nút xóa nhanh để người dùng reset filter dễ dàng
|
|
25
|
+
- Khi cần lắng nghe cả hai luồng: giá trị tức thời (`outValueChange`) và giá trị đã được debounce (`outSearch`)
|
|
26
|
+
|
|
27
|
+
## Cài đặt
|
|
17
28
|
|
|
18
29
|
```bash
|
|
19
30
|
npm install @libs-ui/components-inputs-search
|
|
20
31
|
```
|
|
21
32
|
|
|
22
|
-
##
|
|
23
|
-
|
|
24
|
-
### Import Module
|
|
33
|
+
## Import
|
|
25
34
|
|
|
26
35
|
```typescript
|
|
27
36
|
import { LibsUiComponentsInputsSearchComponent } from '@libs-ui/components-inputs-search';
|
|
@@ -31,105 +40,254 @@ import { LibsUiComponentsInputsSearchComponent } from '@libs-ui/components-input
|
|
|
31
40
|
imports: [LibsUiComponentsInputsSearchComponent],
|
|
32
41
|
// ...
|
|
33
42
|
})
|
|
34
|
-
export class
|
|
43
|
+
export class MyComponent {}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Nếu cần dùng interface `IInputSearchConfig`:
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
import {
|
|
50
|
+
LibsUiComponentsInputsSearchComponent,
|
|
51
|
+
IInputSearchConfig,
|
|
52
|
+
} from '@libs-ui/components-inputs-search';
|
|
35
53
|
```
|
|
36
54
|
|
|
37
|
-
|
|
55
|
+
## Ví dụ sử dụng
|
|
56
|
+
|
|
57
|
+
### Ví dụ 1 — Cơ bản
|
|
58
|
+
|
|
59
|
+
```html
|
|
60
|
+
<libs_ui-components-inputs-search
|
|
61
|
+
(outSearch)="handlerSearch($event)">
|
|
62
|
+
</libs_ui-components-inputs-search>
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
```typescript
|
|
66
|
+
handlerSearch(event: Event, keyword: string): void {
|
|
67
|
+
event.stopPropagation();
|
|
68
|
+
// keyword đã được trim, chỉ emit sau debounce hoặc khi nhấn Enter
|
|
69
|
+
this.loadData({ search: keyword });
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
> Lưu ý: `outSearch` emit kiểu `string` (không phải `Event`). Để gọi `event.stopPropagation()`, hãy xem hướng dẫn tại phần @Output bên dưới.
|
|
74
|
+
|
|
75
|
+
### Ví dụ 2 — Với placeholder và nút xóa nhanh
|
|
38
76
|
|
|
39
77
|
```html
|
|
40
78
|
<libs_ui-components-inputs-search
|
|
41
|
-
(outSearch)="onSearch($event)"
|
|
42
79
|
[searchConfig]="{
|
|
43
80
|
placeholder: 'Tìm kiếm khách hàng...',
|
|
44
81
|
hasClearSearch: true
|
|
45
|
-
}"
|
|
82
|
+
}"
|
|
83
|
+
(outSearch)="handlerSearch($event)">
|
|
84
|
+
</libs_ui-components-inputs-search>
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
```typescript
|
|
88
|
+
handlerSearch(keyword: string): void {
|
|
89
|
+
// keyword = '' khi người dùng nhấn nút xóa (X)
|
|
90
|
+
this.params.update(p => ({ ...p, search: keyword, page: 1 }));
|
|
91
|
+
this.loadList();
|
|
92
|
+
}
|
|
46
93
|
```
|
|
47
94
|
|
|
48
|
-
### Tùy chỉnh
|
|
95
|
+
### Ví dụ 3 — Tùy chỉnh debounce và icon
|
|
49
96
|
|
|
50
97
|
```html
|
|
51
98
|
<libs_ui-components-inputs-search
|
|
52
99
|
[debounceTime]="500"
|
|
53
100
|
[searchConfig]="{
|
|
54
101
|
iconLeftClass: 'libs-ui-icon-filter',
|
|
55
|
-
placeholder: 'Lọc nhanh...'
|
|
102
|
+
placeholder: 'Lọc nhanh...',
|
|
103
|
+
noBorder: true,
|
|
104
|
+
backgroundNone: true
|
|
56
105
|
}"
|
|
57
|
-
(outSearch)="
|
|
106
|
+
(outSearch)="handlerFilter($event)">
|
|
107
|
+
</libs_ui-components-inputs-search>
|
|
58
108
|
```
|
|
59
109
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
110
|
+
```typescript
|
|
111
|
+
handlerFilter(keyword: string): void {
|
|
112
|
+
this.filterKeyword.set(keyword);
|
|
113
|
+
}
|
|
114
|
+
```
|
|
63
115
|
|
|
64
|
-
|
|
65
|
-
| :--------------------------- | :------------------- | :------- | :-------------------------------------------------------- |
|
|
66
|
-
| `searchConfig` | `IInputSearchConfig` | `{}` | Cấu hình cho ô tìm kiếm (placeholder, value, icons, ...). |
|
|
67
|
-
| `blurTimeOut` | `number` | `600` | Thời gian chờ trước khi emit sự kiện blur. |
|
|
68
|
-
| `debounceTime` | `number` | `1000` | Thời gian chờ (ms) trước khi phát ra `outSearch`. |
|
|
69
|
-
| `disable` | `boolean` | `false` | Vô hiệu hóa ô tìm kiếm. |
|
|
70
|
-
| `focusTimeOut` | `number` | `600` | Thời gian chờ trước khi emit sự kiện focus. |
|
|
71
|
-
| `ignoreAutoComplete` | `boolean` | `false` | Nếu true, sẽ không tự động emit `outSearch`. |
|
|
72
|
-
| `ignoreStopPropagationEvent` | `boolean` | `false` | Ngăn chặn sự kiện lan truyền ra ngoài. |
|
|
73
|
-
| `readonly` | `boolean` | `false` | Chế độ chỉ đọc. |
|
|
116
|
+
### Ví dụ 4 — Lắng nghe từng keystroke (outValueChange)
|
|
74
117
|
|
|
75
|
-
|
|
118
|
+
```html
|
|
119
|
+
<libs_ui-components-inputs-search
|
|
120
|
+
[ignoreAutoComplete]="true"
|
|
121
|
+
(outValueChange)="handlerValueChange($event)"
|
|
122
|
+
(outSearch)="handlerSearch($event)">
|
|
123
|
+
</libs_ui-components-inputs-search>
|
|
124
|
+
```
|
|
76
125
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
| `outIconRight` | `string` | Sự kiện khi click vào icon bên phải. |
|
|
83
|
-
| `outSearch` | `string` | Phát ra nội dung tìm kiếm sau khoảng thời gian debounce hoặc khi nhấn Enter. |
|
|
84
|
-
| `outValueChange` | `string` | Phát ra nội dung mới ngay lập tức mỗi khi gõ phím. |
|
|
126
|
+
```typescript
|
|
127
|
+
handlerValueChange(keyword: string): void {
|
|
128
|
+
// Emit mỗi lần gõ — dùng để hiển thị gợi ý realtime
|
|
129
|
+
this.suggestionKeyword.set(keyword);
|
|
130
|
+
}
|
|
85
131
|
|
|
86
|
-
|
|
132
|
+
handlerSearch(keyword: string): void {
|
|
133
|
+
// Chỉ emit khi nhấn Enter (ignoreAutoComplete = true bỏ qua debounce)
|
|
134
|
+
this.executeSearch(keyword);
|
|
135
|
+
}
|
|
136
|
+
```
|
|
87
137
|
|
|
88
|
-
###
|
|
138
|
+
### Ví dụ 5 — Điều khiển programmatically qua FunctionsControl
|
|
89
139
|
|
|
90
|
-
|
|
140
|
+
```html
|
|
141
|
+
<libs_ui-components-inputs-search
|
|
142
|
+
[searchConfig]="{ placeholder: 'Tìm kiếm...' }"
|
|
143
|
+
(outFunctionsControl)="handlerFunctionsControl($event)"
|
|
144
|
+
(outSearch)="handlerSearch($event)">
|
|
145
|
+
</libs_ui-components-inputs-search>
|
|
146
|
+
```
|
|
91
147
|
|
|
92
148
|
```typescript
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
149
|
+
import { IInputFunctionControlEvent } from '@libs-ui/components-inputs-input';
|
|
150
|
+
|
|
151
|
+
private searchControl: IInputFunctionControlEvent | undefined;
|
|
152
|
+
|
|
153
|
+
handlerFunctionsControl(control: IInputFunctionControlEvent): void {
|
|
154
|
+
this.searchControl = control;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Focus ô tìm kiếm từ code
|
|
158
|
+
focusSearchInput(): void {
|
|
159
|
+
this.searchControl?.focus();
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Reset giá trị từ code
|
|
163
|
+
resetSearch(): void {
|
|
164
|
+
this.searchControl?.resetValue();
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
handlerSearch(keyword: string): void {
|
|
168
|
+
this.executeSearch(keyword);
|
|
106
169
|
}
|
|
107
170
|
```
|
|
108
171
|
|
|
109
|
-
|
|
172
|
+
## @Input()
|
|
173
|
+
|
|
174
|
+
| Input | Type | Default | Mô tả | Ví dụ |
|
|
175
|
+
|---|---|---|---|---|
|
|
176
|
+
| `blurTimeOut` | `number` | `600` | Thời gian chờ (ms) trước khi emit sự kiện blur | `[blurTimeOut]="300"` |
|
|
177
|
+
| `debounceTime` | `number` | `1000` | Thời gian chờ (ms) sau khi người dùng ngừng gõ để emit `outSearch` | `[debounceTime]="500"` |
|
|
178
|
+
| `disable` | `boolean` | `false` | Vô hiệu hóa toàn bộ ô tìm kiếm | `[disable]="isLoading()"` |
|
|
179
|
+
| `focusTimeOut` | `number` | `600` | Thời gian chờ (ms) trước khi emit sự kiện focus | `[focusTimeOut]="300"` |
|
|
180
|
+
| `ignoreAutoComplete` | `boolean` | `undefined` | Nếu `true`, bỏ qua debounce — chỉ emit `outSearch` khi nhấn Enter | `[ignoreAutoComplete]="true"` |
|
|
181
|
+
| `ignoreStopPropagationEvent` | `boolean` | `false` | Không gọi `stopPropagation` cho các DOM event bên trong | `[ignoreStopPropagationEvent]="true"` |
|
|
182
|
+
| `readonly` | `boolean` | `false` | Chỉ hiển thị, không cho phép nhập liệu | `[readonly]="true"` |
|
|
183
|
+
| `searchConfig` | `IInputSearchConfig` | `{}` | Cấu hình chi tiết giao diện ô tìm kiếm (xem bảng `IInputSearchConfig`) | `[searchConfig]="searchConfig()"` |
|
|
184
|
+
|
|
185
|
+
### IInputSearchConfig
|
|
186
|
+
|
|
187
|
+
| Thuộc tính | Type | Mặc định | Mô tả | Ví dụ |
|
|
188
|
+
|---|---|---|---|---|
|
|
189
|
+
| `backgroundNone` | `boolean` | `false` | Xóa màu nền của ô input | `backgroundNone: true` |
|
|
190
|
+
| `classContainerInput` | `string` | `''` | Class CSS bổ sung cho phần tử bọc input | `classContainerInput: 'rounded-full'` |
|
|
191
|
+
| `classCoverInputSearch` | `string` | `undefined` | Class CSS bổ sung cho lớp ngoài cùng của search | `classCoverInputSearch: 'w-64'` |
|
|
192
|
+
| `classInclude` | `string` | `undefined` | Class CSS bổ sung truyền xuống component Input | `classInclude: 'border-blue-500'` |
|
|
193
|
+
| `defaultHeight` | `number` | `32` | Chiều cao mặc định (px) của ô input | `defaultHeight: 36` |
|
|
194
|
+
| `hasClearSearch` | `boolean` | `undefined` | Hiển thị nút xóa (X) khi ô có nội dung | `hasClearSearch: true` |
|
|
195
|
+
| `iconLeftClass` | `string` | `'libs-ui-icon-search'` | Class icon phía trái | `iconLeftClass: 'libs-ui-icon-filter'` |
|
|
196
|
+
| `iconRightClass` | `string` | `undefined` | Class icon phía phải (thêm vào sau icon xóa nếu có) | `iconRightClass: 'libs-ui-icon-info'` |
|
|
197
|
+
| `noBorder` | `boolean` | `false` | Ẩn đường viền của ô input | `noBorder: true` |
|
|
198
|
+
| `placeholder` | `string` | `'i18n_search'` | Placeholder của ô input (hỗ trợ i18n key) | `placeholder: 'Tìm kiếm...'` |
|
|
199
|
+
| `popoverContentIconRight` | `string` | `''` | Nội dung popover hiển thị khi hover icon phải | `popoverContentIconRight: 'i18n_search_hint'` |
|
|
200
|
+
| `value` | `string` | `undefined` | Giá trị khởi tạo của ô tìm kiếm | `value: 'từ khóa ban đầu'` |
|
|
201
|
+
|
|
202
|
+
## @Output()
|
|
110
203
|
|
|
111
|
-
|
|
204
|
+
| Output | Type | Mô tả | Handler TS | Binding HTML |
|
|
205
|
+
|---|---|---|---|---|
|
|
206
|
+
| `(outFocusAndBlur)` | `IFocusAndBlurEvent` | Emit khi ô input được focus hoặc blur, kèm trạng thái và DOM event | `handlerFocusAndBlur(e: IFocusAndBlurEvent): void { e.event.stopPropagation(); this.isFocused.set(e.focus); }` | `(outFocusAndBlur)="handlerFocusAndBlur($event)"` |
|
|
207
|
+
| `(outFunctionsControl)` | `IInputFunctionControlEvent` | Emit object chứa các hàm điều khiển input: `focus`, `blur`, `resetValue`, `insertContent` | `handlerFunctionsControl(ctrl: IInputFunctionControlEvent): void { this.searchCtrl = ctrl; }` | `(outFunctionsControl)="handlerFunctionsControl($event)"` |
|
|
208
|
+
| `(outIconLeft)` | `string` | Emit tên event khi người dùng click vào icon bên trái | `handlerIconLeft(eventName: string): void { eventName; }` | `(outIconLeft)="handlerIconLeft($event)"` |
|
|
209
|
+
| `(outIconRight)` | `string` | Emit tên event khi người dùng click vào icon bên phải (ngoài hành vi xóa) | `handlerIconRight(eventName: string): void { eventName; }` | `(outIconRight)="handlerIconRight($event)"` |
|
|
210
|
+
| `(outSearch)` | `string` | Emit chuỗi tìm kiếm (đã trim) sau debounce hoặc khi nhấn Enter. Emit `''` khi người dùng xóa hết hoặc nhấn nút xóa | `handlerSearch(keyword: string): void { this.loadData({ search: keyword }); }` | `(outSearch)="handlerSearch($event)"` |
|
|
211
|
+
| `(outValueChange)` | `string` | Emit chuỗi ngay lập tức mỗi khi giá trị input thay đổi (mỗi keystroke) | `handlerValueChange(keyword: string): void { this.currentValue.set(keyword); }` | `(outValueChange)="handlerValueChange($event)"` |
|
|
212
|
+
|
|
213
|
+
## Types & Interfaces
|
|
112
214
|
|
|
113
215
|
```typescript
|
|
216
|
+
import {
|
|
217
|
+
IInputSearchConfig,
|
|
218
|
+
} from '@libs-ui/components-inputs-search';
|
|
219
|
+
|
|
220
|
+
// IInputFunctionControlEvent và IFocusAndBlurEvent được re-export từ:
|
|
221
|
+
import {
|
|
222
|
+
IInputFunctionControlEvent,
|
|
223
|
+
IFocusAndBlurEvent,
|
|
224
|
+
} from '@libs-ui/components-inputs-input';
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
```typescript
|
|
228
|
+
export interface IInputSearchConfig {
|
|
229
|
+
classInclude?: string; // Class CSS bổ sung cho component Input bên trong
|
|
230
|
+
classContainerInput?: string; // Class CSS cho phần tử bọc input
|
|
231
|
+
placeholder?: string; // Placeholder (hỗ trợ i18n key)
|
|
232
|
+
value?: string; // Giá trị khởi tạo
|
|
233
|
+
noBorder?: boolean; // Ẩn border
|
|
234
|
+
backgroundNone?: boolean; // Xóa background
|
|
235
|
+
iconLeftClass?: string; // Class icon trái (mặc định: 'libs-ui-icon-search')
|
|
236
|
+
iconRightClass?: string; // Class icon phải
|
|
237
|
+
defaultHeight?: number; // Chiều cao (px), mặc định: 32
|
|
238
|
+
classCoverInputSearch?: string; // Class cho wrapper ngoài cùng
|
|
239
|
+
hasClearSearch?: boolean; // Bật nút xóa nhanh (X)
|
|
240
|
+
popoverContentIconRight?: string; // Nội dung popover icon phải
|
|
241
|
+
}
|
|
242
|
+
|
|
114
243
|
export interface IInputFunctionControlEvent {
|
|
115
244
|
focus: (emitEvent?: boolean) => Promise<void>;
|
|
116
245
|
blur: (emitEvent?: boolean) => Promise<void>;
|
|
117
246
|
resetValue: () => Promise<void>;
|
|
118
247
|
insertContent: (data: string | number) => Promise<void>;
|
|
119
|
-
//
|
|
248
|
+
// Các method khác từ @libs-ui/components-inputs-input
|
|
120
249
|
}
|
|
121
250
|
|
|
122
251
|
export interface IFocusAndBlurEvent {
|
|
123
|
-
focus: boolean;
|
|
252
|
+
focus: boolean; // true = đang focus, false = đã blur
|
|
124
253
|
event: FocusEvent;
|
|
125
254
|
}
|
|
126
255
|
```
|
|
127
256
|
|
|
128
|
-
##
|
|
257
|
+
## Logic ẩn cần biết
|
|
258
|
+
|
|
259
|
+
**Cơ chế debounce và Enter hoạt động độc lập:**
|
|
260
|
+
|
|
261
|
+
- Khi người dùng gõ: `outSearch` emit sau `debounceTime` ms kể từ keystroke cuối.
|
|
262
|
+
- Khi người dùng nhấn Enter: `outSearch` emit ngay lập tức (có throttle với cùng `debounceTime` để chống spam).
|
|
263
|
+
- Khi người dùng nhấn Enter trong lúc debounce đang đếm: debounce bị hủy, `outSearch` chỉ emit 1 lần từ luồng Enter.
|
|
264
|
+
|
|
265
|
+
**Hành vi xóa nội dung (`hasClearSearch: true`):**
|
|
266
|
+
|
|
267
|
+
- Khi ô có nội dung, icon phải tự động chuyển thành icon xóa (X).
|
|
268
|
+
- Nhấn X: `valueSearch` reset về `''` và `outSearch` emit `''` ngay lập tức (không qua debounce).
|
|
269
|
+
- Khi xóa hết bằng bàn phím: `outSearch` emit `''` sau `debounceTime / 2` ms.
|
|
129
270
|
|
|
130
|
-
|
|
131
|
-
- **Base**: `@libs-ui/components-inputs-input`
|
|
271
|
+
**`ignoreAutoComplete` = `true`:**
|
|
132
272
|
|
|
133
|
-
|
|
273
|
+
- Hoàn toàn vô hiệu hóa luồng debounce.
|
|
274
|
+
- `outSearch` chỉ emit khi người dùng nhấn Enter.
|
|
275
|
+
- Thích hợp cho các ô tìm kiếm cần người dùng xác nhận trước khi gửi.
|
|
276
|
+
|
|
277
|
+
## Lưu ý quan trọng
|
|
278
|
+
|
|
279
|
+
⚠️ **Debounce mặc định 1000ms**: Nếu UX cần phản hồi nhanh hơn (ví dụ filter local), hãy giảm `[debounceTime]="300"` hoặc `[debounceTime]="500"`.
|
|
280
|
+
|
|
281
|
+
⚠️ **outSearch emit chuỗi rỗng khi xóa**: Khi người dùng xóa hết nội dung hoặc nhấn nút X, `outSearch` sẽ emit `''`. Handler phải xử lý trường hợp này (ví dụ: reset filter, load lại toàn bộ danh sách).
|
|
282
|
+
|
|
283
|
+
⚠️ **value trong searchConfig chỉ là giá trị khởi tạo**: Sau khi component khởi tạo, thay đổi `searchConfig().value` từ bên ngoài không tự động cập nhật giao diện. Dùng `FunctionsControl.resetValue()` hoặc `FunctionsControl.insertContent()` để cập nhật programmatically.
|
|
284
|
+
|
|
285
|
+
⚠️ **outValueChange vs outSearch**: Dùng `outValueChange` khi cần phản hồi tức thì (ví dụ: highlight từ khóa, đếm ký tự). Dùng `outSearch` cho các tác vụ tốn tài nguyên (gọi API).
|
|
286
|
+
|
|
287
|
+
## Demo
|
|
288
|
+
|
|
289
|
+
```bash
|
|
290
|
+
npx nx serve core-ui
|
|
291
|
+
```
|
|
134
292
|
|
|
135
|
-
|
|
293
|
+
Truy cập: http://localhost:4500/components/inputs/search
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { signal, input, output,
|
|
2
|
+
import { signal, input, output, Component, ChangeDetectionStrategy } from '@angular/core';
|
|
3
3
|
import { LibsUiComponentsInputsInputComponent } from '@libs-ui/components-inputs-input';
|
|
4
4
|
import * as i1 from '@ngx-translate/core';
|
|
5
5
|
import { TranslateModule } from '@ngx-translate/core';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"libs-ui-components-inputs-search.mjs","sources":["../../../../../../libs-ui/components/inputs/search/src/search.component.ts","../../../../../../libs-ui/components/inputs/search/src/search.component.html","../../../../../../libs-ui/components/inputs/search/src/libs-ui-components-inputs-search.ts"],"sourcesContent":["import { ChangeDetectionStrategy, Component, OnDestroy, OnInit, input, output, signal } from '@angular/core';\nimport { IFocusAndBlurEvent, IInputFunctionControlEvent, LibsUiComponentsInputsInputComponent } from '@libs-ui/components-inputs-input';\nimport { IEvent } from '@libs-ui/interfaces-types';\nimport { TranslateModule } from '@ngx-translate/core';\nimport { Subject } from 'rxjs';\nimport { debounceTime, filter, takeUntil, throttleTime } from 'rxjs/operators';\nimport { IInputSearchConfig } from './interfaces/config.interface';\n\n@Component({\n // eslint-disable-next-line @angular-eslint/component-selector\n selector: 'libs_ui-components-inputs-search',\n templateUrl: './search.component.html',\n standalone: true,\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [TranslateModule, LibsUiComponentsInputsInputComponent],\n})\nexport class LibsUiComponentsInputsSearchComponent implements OnInit, OnDestroy {\n // #region PROPERTY\n protected valueSearch = signal<string>('');\n\n private readonly inputFunctionControl = signal<IInputFunctionControlEvent | undefined>(undefined);\n private readonly onDestroy = new Subject<void>();\n private readonly onSearch: Subject<string> = new Subject();\n private readonly onEnter: Subject<string> = new Subject();\n private readonly timeout = signal<number>(0);\n private readonly searchingWhileEntering = signal<boolean>(false);\n\n // #region INPUT\n readonly disable = input<boolean>(false);\n readonly readonly = input<boolean>(false);\n readonly searchConfig = input<IInputSearchConfig, IInputSearchConfig>({}, { transform: (value) => value || {} });\n readonly ignoreAutoComplete = input<boolean>(); // không emit sự kiện sau 1 khoảng thời gian người dùng ngừng nhập\n readonly debounceTime = input<number, number>(1000, { transform: (value) => value ?? 1000 });\n readonly ignoreStopPropagationEvent = input<boolean>(false);\n readonly focusTimeOut = input<number, number>(600, { transform: (value) => value ?? 600 });\n readonly blurTimeOut = input<number, number>(600, { transform: (value) => value ?? 600 });\n\n // #region OUTPUT\n readonly outSearch = output<string>(); // sau 1 khoảng thời gian người dùng ngừng nhập sẽ emit sự kiện\n readonly outValueChange = output<string>(); // sử dụng khi muốn lắng nghe mỗi lần gõ text\n readonly outIconLeft = output<string>();\n readonly outIconRight = output<string>();\n readonly outFocusAndBlur = output<IFocusAndBlurEvent>();\n readonly outFunctionsControl = output<IInputFunctionControlEvent>();\n\n ngOnInit(): void {\n this.valueSearch.set(this.searchConfig()?.value || '');\n this.onSearch\n .pipe(\n debounceTime(this.debounceTime()),\n filter((keySearch) => !!keySearch),\n takeUntil(this.onDestroy)\n )\n .subscribe((keySearch) => {\n if (this.searchingWhileEntering() || this.ignoreAutoComplete() || !this.valueSearch()) {\n this.searchingWhileEntering.set(false);\n\n return;\n }\n this.outSearch.emit(`${keySearch}`.trim());\n });\n this.onEnter.pipe(throttleTime(this.debounceTime()), takeUntil(this.onDestroy)).subscribe((keySearch) => {\n this.outSearch.emit(`${keySearch}`.trim());\n });\n }\n\n // #region FUNCTIONS\n protected handlerValueChange(keySearch: string) {\n this.outValueChange.emit(keySearch.toString());\n this.valueSearch.set(keySearch);\n this.searchingWhileEntering.set(false);\n if (this.valueSearch()) {\n this.onSearch.next(this.valueSearch());\n return;\n }\n\n clearTimeout(this.timeout());\n this.timeout.set(\n setTimeout(() => {\n if (!this.valueSearch() && !this.ignoreAutoComplete()) {\n this.outSearch.emit(this.valueSearch());\n }\n }, this.debounceTime() / 2)\n );\n }\n\n protected handlerEnterInput(e: IEvent) {\n this.valueSearch.set(e.target.value);\n this.searchingWhileEntering.set(true);\n this.onEnter.next(this.valueSearch());\n }\n\n protected handlerEventIconLeft(eventName: string) {\n this.outIconLeft.emit(eventName);\n }\n\n protected handlerEventIconRight(eventName: string) {\n if (this.searchConfig()?.hasClearSearch) {\n this.valueSearch.set('');\n this.outSearch.emit(this.valueSearch());\n }\n this.outIconRight.emit(eventName);\n }\n\n protected handlerFunctionControl(event: IInputFunctionControlEvent) {\n this.outFunctionsControl.emit(event);\n this.inputFunctionControl.set(event);\n }\n\n public get FunctionsControl(): IInputFunctionControlEvent | undefined {\n return this.inputFunctionControl();\n }\n\n protected handlerFocusAndBlur(event: IFocusAndBlurEvent) {\n this.outFocusAndBlur.emit(event);\n }\n\n ngOnDestroy(): void {\n clearTimeout(this.timeout());\n this.onDestroy.next();\n this.onDestroy.complete();\n }\n}\n","@let constHtmlPlaceholder = searchConfig().placeholder || 'i18n_search';\n<libs_ui-components-inputs-input\n [disable]=\"disable()\"\n [readonly]=\"readonly()\"\n [ignoreStopPropagationEvent]=\"ignoreStopPropagationEvent()\"\n [defaultHeight]=\"searchConfig().defaultHeight || 32\"\n [classInclude]=\"'w-full ' + (searchConfig().classInclude ? searchConfig().classInclude : '')\"\n [iconLeftClass]=\"searchConfig().iconLeftClass ?? 'libs-ui-icon-search'\"\n [iconRightClass]=\"(searchConfig().hasClearSearch && valueSearch() ? 'libs-ui-icon-close-circle-solid cursor-pointer ' : '') + (searchConfig().iconRightClass ? ' ' + searchConfig().iconRightClass : '')\"\n [setIconRightColorSameColorDisableReadOnly]=\"searchConfig().hasClearSearch && valueSearch() ? true : false\"\n [value]=\"searchConfig().value ?? this.valueSearch()\"\n [placeholder]=\"constHtmlPlaceholder | translate\"\n [noBorder]=\"searchConfig().noBorder || false\"\n [backgroundNone]=\"searchConfig().backgroundNone || false\"\n [classContainerInput]=\"searchConfig().classContainerInput || ''\"\n [popoverContentIconRight]=\"searchConfig().popoverContentIconRight || ''\"\n [focusTimeOut]=\"focusTimeOut()\"\n [blurTimeOut]=\"blurTimeOut()\"\n (outChange)=\"handlerValueChange($event)\"\n (outIconLeft)=\"handlerEventIconLeft($event)\"\n (outIconRight)=\"handlerEventIconRight($event)\"\n (outFunctionsControl)=\"handlerFunctionControl($event)\"\n (outEnterEvent)=\"handlerEnterInput($event)\"\n (outFocusAndBlurEvent)=\"handlerFocusAndBlur($event)\" />\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"libs-ui-components-inputs-search.mjs","sources":["../../../../../../libs-ui/components/inputs/search/src/search.component.ts","../../../../../../libs-ui/components/inputs/search/src/search.component.html","../../../../../../libs-ui/components/inputs/search/src/libs-ui-components-inputs-search.ts"],"sourcesContent":["import { ChangeDetectionStrategy, Component, OnDestroy, OnInit, input, output, signal } from '@angular/core';\nimport { IFocusAndBlurEvent, IInputFunctionControlEvent, LibsUiComponentsInputsInputComponent } from '@libs-ui/components-inputs-input';\nimport { IEvent } from '@libs-ui/interfaces-types';\nimport { TranslateModule } from '@ngx-translate/core';\nimport { Subject } from 'rxjs';\nimport { debounceTime, filter, takeUntil, throttleTime } from 'rxjs/operators';\nimport { IInputSearchConfig } from './interfaces/config.interface';\n\n@Component({\n // eslint-disable-next-line @angular-eslint/component-selector\n selector: 'libs_ui-components-inputs-search',\n templateUrl: './search.component.html',\n standalone: true,\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [TranslateModule, LibsUiComponentsInputsInputComponent],\n})\nexport class LibsUiComponentsInputsSearchComponent implements OnInit, OnDestroy {\n // #region PROPERTY\n protected valueSearch = signal<string>('');\n\n private readonly inputFunctionControl = signal<IInputFunctionControlEvent | undefined>(undefined);\n private readonly onDestroy = new Subject<void>();\n private readonly onSearch: Subject<string> = new Subject();\n private readonly onEnter: Subject<string> = new Subject();\n private readonly timeout = signal<number>(0);\n private readonly searchingWhileEntering = signal<boolean>(false);\n\n // #region INPUT\n readonly disable = input<boolean>(false);\n readonly readonly = input<boolean>(false);\n readonly searchConfig = input<IInputSearchConfig, IInputSearchConfig>({}, { transform: (value) => value || {} });\n readonly ignoreAutoComplete = input<boolean>(); // không emit sự kiện sau 1 khoảng thời gian người dùng ngừng nhập\n readonly debounceTime = input<number, number>(1000, { transform: (value) => value ?? 1000 });\n readonly ignoreStopPropagationEvent = input<boolean>(false);\n readonly focusTimeOut = input<number, number>(600, { transform: (value) => value ?? 600 });\n readonly blurTimeOut = input<number, number>(600, { transform: (value) => value ?? 600 });\n\n // #region OUTPUT\n readonly outSearch = output<string>(); // sau 1 khoảng thời gian người dùng ngừng nhập sẽ emit sự kiện\n readonly outValueChange = output<string>(); // sử dụng khi muốn lắng nghe mỗi lần gõ text\n readonly outIconLeft = output<string>();\n readonly outIconRight = output<string>();\n readonly outFocusAndBlur = output<IFocusAndBlurEvent>();\n readonly outFunctionsControl = output<IInputFunctionControlEvent>();\n\n ngOnInit(): void {\n this.valueSearch.set(this.searchConfig()?.value || '');\n this.onSearch\n .pipe(\n debounceTime(this.debounceTime()),\n filter((keySearch) => !!keySearch),\n takeUntil(this.onDestroy)\n )\n .subscribe((keySearch) => {\n if (this.searchingWhileEntering() || this.ignoreAutoComplete() || !this.valueSearch()) {\n this.searchingWhileEntering.set(false);\n\n return;\n }\n this.outSearch.emit(`${keySearch}`.trim());\n });\n this.onEnter.pipe(throttleTime(this.debounceTime()), takeUntil(this.onDestroy)).subscribe((keySearch) => {\n this.outSearch.emit(`${keySearch}`.trim());\n });\n }\n\n // #region FUNCTIONS\n protected handlerValueChange(keySearch: string) {\n this.outValueChange.emit(keySearch.toString());\n this.valueSearch.set(keySearch);\n this.searchingWhileEntering.set(false);\n if (this.valueSearch()) {\n this.onSearch.next(this.valueSearch());\n return;\n }\n\n clearTimeout(this.timeout());\n this.timeout.set(\n setTimeout(() => {\n if (!this.valueSearch() && !this.ignoreAutoComplete()) {\n this.outSearch.emit(this.valueSearch());\n }\n }, this.debounceTime() / 2)\n );\n }\n\n protected handlerEnterInput(e: IEvent) {\n this.valueSearch.set(e.target.value);\n this.searchingWhileEntering.set(true);\n this.onEnter.next(this.valueSearch());\n }\n\n protected handlerEventIconLeft(eventName: string) {\n this.outIconLeft.emit(eventName);\n }\n\n protected handlerEventIconRight(eventName: string) {\n if (this.searchConfig()?.hasClearSearch) {\n this.valueSearch.set('');\n this.outSearch.emit(this.valueSearch());\n }\n this.outIconRight.emit(eventName);\n }\n\n protected handlerFunctionControl(event: IInputFunctionControlEvent) {\n this.outFunctionsControl.emit(event);\n this.inputFunctionControl.set(event);\n }\n\n public get FunctionsControl(): IInputFunctionControlEvent | undefined {\n return this.inputFunctionControl();\n }\n\n protected handlerFocusAndBlur(event: IFocusAndBlurEvent) {\n this.outFocusAndBlur.emit(event);\n }\n\n ngOnDestroy(): void {\n clearTimeout(this.timeout());\n this.onDestroy.next();\n this.onDestroy.complete();\n }\n}\n","@let constHtmlPlaceholder = searchConfig().placeholder || 'i18n_search';\n<libs_ui-components-inputs-input\n [disable]=\"disable()\"\n [readonly]=\"readonly()\"\n [ignoreStopPropagationEvent]=\"ignoreStopPropagationEvent()\"\n [defaultHeight]=\"searchConfig().defaultHeight || 32\"\n [classInclude]=\"'w-full ' + (searchConfig().classInclude ? searchConfig().classInclude : '')\"\n [iconLeftClass]=\"searchConfig().iconLeftClass ?? 'libs-ui-icon-search'\"\n [iconRightClass]=\"(searchConfig().hasClearSearch && valueSearch() ? 'libs-ui-icon-close-circle-solid cursor-pointer ' : '') + (searchConfig().iconRightClass ? ' ' + searchConfig().iconRightClass : '')\"\n [setIconRightColorSameColorDisableReadOnly]=\"searchConfig().hasClearSearch && valueSearch() ? true : false\"\n [value]=\"searchConfig().value ?? this.valueSearch()\"\n [placeholder]=\"constHtmlPlaceholder | translate\"\n [noBorder]=\"searchConfig().noBorder || false\"\n [backgroundNone]=\"searchConfig().backgroundNone || false\"\n [classContainerInput]=\"searchConfig().classContainerInput || ''\"\n [popoverContentIconRight]=\"searchConfig().popoverContentIconRight || ''\"\n [focusTimeOut]=\"focusTimeOut()\"\n [blurTimeOut]=\"blurTimeOut()\"\n (outChange)=\"handlerValueChange($event)\"\n (outIconLeft)=\"handlerEventIconLeft($event)\"\n (outIconRight)=\"handlerEventIconRight($event)\"\n (outFunctionsControl)=\"handlerFunctionControl($event)\"\n (outEnterEvent)=\"handlerEnterInput($event)\"\n (outFocusAndBlurEvent)=\"handlerFocusAndBlur($event)\" />\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@libs-ui/components-inputs-search",
|
|
3
|
-
"version": "0.2.356-
|
|
3
|
+
"version": "0.2.356-43",
|
|
4
4
|
"peerDependencies": {
|
|
5
5
|
"@angular/core": ">=18.0.0",
|
|
6
|
-
"@libs-ui/components-inputs-input": "0.2.356-
|
|
7
|
-
"@libs-ui/interfaces-types": "0.2.356-
|
|
6
|
+
"@libs-ui/components-inputs-input": "0.2.356-43",
|
|
7
|
+
"@libs-ui/interfaces-types": "0.2.356-43",
|
|
8
8
|
"@ngx-translate/core": "^15.0.0",
|
|
9
9
|
"rxjs": "~7.8.0"
|
|
10
10
|
},
|