@libs-ui/components-inputs-input 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,53 +1,38 @@
|
|
|
1
1
|
# @libs-ui/components-inputs-input
|
|
2
2
|
|
|
3
|
-
> Universal input component hỗ trợ text, number, textarea với validation và customization đầy
|
|
4
|
-
|
|
5
|
-
**Version:** 0.2.355-14
|
|
3
|
+
> Universal input component hỗ trợ text, number, textarea và iframe-textarea với validation, formatting và customization đầy đủ.
|
|
6
4
|
|
|
7
5
|
## Giới thiệu
|
|
8
6
|
|
|
9
|
-
`LibsUiComponentsInputsInputComponent` là
|
|
7
|
+
`LibsUiComponentsInputsInputComponent` là Angular standalone component đa năng cho việc nhập liệu. Component hỗ trợ 4 kiểu dữ liệu (`string`, `int`, `float`, `bigint`), 3 loại tag (`input`, `textarea`, `iframe-textarea`), tự động format number theo locale (VI/EN), auto-resize textarea, và cung cấp API điều khiển ngoài qua `FunctionsControl`. Tích hợp sẵn OnPush Change Detection và Angular Signals.
|
|
10
8
|
|
|
11
|
-
|
|
9
|
+
## Tính năng
|
|
12
10
|
|
|
13
|
-
- ✅ Hỗ trợ
|
|
14
|
-
- ✅ Hỗ trợ
|
|
15
|
-
- ✅
|
|
16
|
-
- ✅
|
|
17
|
-
- ✅
|
|
18
|
-
- ✅
|
|
19
|
-
- ✅ Icon left/right
|
|
20
|
-
- ✅ Template
|
|
21
|
-
- ✅
|
|
22
|
-
- ✅ Drag & drop file
|
|
23
|
-
- ✅
|
|
24
|
-
- ✅
|
|
25
|
-
- ✅ Angular Signals
|
|
11
|
+
- ✅ Hỗ trợ 4 kiểu dữ liệu: `string`, `int`, `float`, `bigint`
|
|
12
|
+
- ✅ Hỗ trợ 3 loại tag: `input`, `textarea`, `iframe-textarea`
|
|
13
|
+
- ✅ Tự động format number theo ngôn ngữ (VI dùng `.` phân cách nghìn, EN dùng `,`)
|
|
14
|
+
- ✅ Auto-resize textarea theo nội dung (min/max height có thể cấu hình)
|
|
15
|
+
- ✅ Validation min/max value cho number input
|
|
16
|
+
- ✅ Hiển thị character count (`showCount`)
|
|
17
|
+
- ✅ Icon left/right kèm popover tooltip
|
|
18
|
+
- ✅ Template slot tùy chỉnh dưới input (trái/phải)
|
|
19
|
+
- ✅ Nút tăng/giảm (up/down) cho number input
|
|
20
|
+
- ✅ Drag & drop file vào input
|
|
21
|
+
- ✅ Điều khiển từ bên ngoài qua `FunctionsControl` (focus, blur, insert, reset, selectAll)
|
|
22
|
+
- ✅ `iframe-textarea`: cô lập CSS toàn cục, style riêng qua `iframeTextareaCustomStyle`
|
|
23
|
+
- ✅ OnPush Change Detection + Angular Signals
|
|
26
24
|
|
|
27
25
|
## Khi nào sử dụng
|
|
28
26
|
|
|
29
27
|
- Cần input field cơ bản cho text hoặc number
|
|
30
|
-
- Cần textarea
|
|
31
|
-
- Cần format number theo locale
|
|
28
|
+
- Cần textarea tự động co giãn theo nội dung
|
|
29
|
+
- Cần format number theo locale VI/EN
|
|
32
30
|
- Cần validation min/max cho number input
|
|
33
|
-
- Cần hiển thị
|
|
34
|
-
- Cần custom
|
|
35
|
-
- Cần
|
|
36
|
-
- Cần drag & drop file vào input
|
|
37
|
-
|
|
38
|
-
## Important Notes
|
|
39
|
-
|
|
40
|
-
⚠️ **Data Type Handling**: Component tự động format number theo ngôn ngữ hiện tại (VI dùng dấu `.` cho thousands, EN dùng `,`).
|
|
41
|
-
|
|
42
|
-
⚠️ **Textarea Auto-resize**: Khi dùng `tagInput="textarea"`, component tự động điều chỉnh height dựa trên content.
|
|
43
|
-
|
|
44
|
-
⚠️ **Number Precision**:
|
|
45
|
-
|
|
46
|
-
- `int`: max 16-17 digits
|
|
47
|
-
- `float`: max 15 digits (font) + decimals
|
|
48
|
-
- `bigint`: configurable via `maxLengthNumberCount` và `fixedFloat`
|
|
49
|
-
|
|
50
|
-
⚠️ **Value Model**: `value` là model (two-way binding), component tự động parse và emit theo `dataType`.
|
|
31
|
+
- Cần hiển thị số ký tự đã nhập
|
|
32
|
+
- Cần custom icon trái/phải với popover tooltip
|
|
33
|
+
- Cần điều khiển input từ component cha (focus, insert text, reset)
|
|
34
|
+
- Cần drag & drop file vào vùng input
|
|
35
|
+
- Cần cô lập editor content khỏi CSS toàn cục (dùng `iframe-textarea`)
|
|
51
36
|
|
|
52
37
|
## Cài đặt
|
|
53
38
|
|
|
@@ -67,17 +52,43 @@ import { LibsUiComponentsInputsInputComponent } from '@libs-ui/components-inputs
|
|
|
67
52
|
export class YourComponent {}
|
|
68
53
|
```
|
|
69
54
|
|
|
70
|
-
|
|
55
|
+
Import thêm types/interfaces khi cần:
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
import {
|
|
59
|
+
LibsUiComponentsInputsInputComponent,
|
|
60
|
+
IInputFunctionControlEvent,
|
|
61
|
+
IFocusAndBlurEvent,
|
|
62
|
+
IIframeTextareaCustomStyle,
|
|
63
|
+
TYPE_DATA_TYPE_INPUT,
|
|
64
|
+
TYPE_TAG_INPUT,
|
|
65
|
+
TYPE_INPUT,
|
|
66
|
+
TYPE_INPUT_RESIZE_MODE,
|
|
67
|
+
TYPE_MODE_INPUT,
|
|
68
|
+
} from '@libs-ui/components-inputs-input';
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Ví dụ sử dụng
|
|
71
72
|
|
|
72
73
|
### Basic Text Input
|
|
73
74
|
|
|
74
75
|
```html
|
|
75
76
|
<libs_ui-components-inputs-input
|
|
76
77
|
[(value)]="textValue"
|
|
77
|
-
[placeholder]="'
|
|
78
|
-
(outChange)="
|
|
78
|
+
[placeholder]="'Nhập nội dung'"
|
|
79
|
+
(outChange)="handlerTextChange($event)" />
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
```typescript
|
|
83
|
+
protected textValue = signal('');
|
|
84
|
+
|
|
85
|
+
handlerTextChange(value: string): void {
|
|
86
|
+
// value đã được emit
|
|
87
|
+
}
|
|
79
88
|
```
|
|
80
89
|
|
|
90
|
+
---
|
|
91
|
+
|
|
81
92
|
### Number Input với Min/Max
|
|
82
93
|
|
|
83
94
|
```html
|
|
@@ -86,179 +97,451 @@ export class YourComponent {}
|
|
|
86
97
|
[(value)]="numberValue"
|
|
87
98
|
[minValueNumber]="0"
|
|
88
99
|
[maxValueNumber]="100"
|
|
89
|
-
[placeholder]="'0-100'"
|
|
100
|
+
[placeholder]="'Nhập số 0-100'"
|
|
101
|
+
(outChange)="handlerNumberChange($event)" />
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
protected numberValue = signal<number>(0);
|
|
106
|
+
|
|
107
|
+
handlerNumberChange(value: number): void {
|
|
108
|
+
// value là number đã được parse
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
### Float Input với Fixed Decimal và Giá trị âm
|
|
115
|
+
|
|
116
|
+
```html
|
|
117
|
+
<libs_ui-components-inputs-input
|
|
118
|
+
[dataType]="'float'"
|
|
119
|
+
[(value)]="floatValue"
|
|
120
|
+
[fixedFloat]="2"
|
|
121
|
+
[acceptNegativeValue]="true"
|
|
122
|
+
[placeholder]="'Nhập số thực (vd: -99.99)'"
|
|
123
|
+
(outChange)="handlerFloatChange($event)" />
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
protected floatValue = signal<number>(0);
|
|
128
|
+
|
|
129
|
+
handlerFloatChange(value: number): void {
|
|
130
|
+
// value là số thực, tối đa 2 chữ số thập phân
|
|
131
|
+
}
|
|
90
132
|
```
|
|
91
133
|
|
|
92
|
-
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
### Bigint Input với Precision tùy chỉnh
|
|
137
|
+
|
|
138
|
+
```html
|
|
139
|
+
<libs_ui-components-inputs-input
|
|
140
|
+
[dataType]="'bigint'"
|
|
141
|
+
[(value)]="bigintValue"
|
|
142
|
+
[maxLengthNumberCount]="19"
|
|
143
|
+
[fixedFloat]="4"
|
|
144
|
+
[placeholder]="'Nhập giá trị lớn'"
|
|
145
|
+
(outChange)="handlerBigintChange($event)" />
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
```typescript
|
|
149
|
+
protected bigintValue = signal('');
|
|
150
|
+
|
|
151
|
+
handlerBigintChange(value: string): void {
|
|
152
|
+
// bigint trả về string thay vì number
|
|
153
|
+
}
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
### Textarea với Auto-resize và Character Count
|
|
93
159
|
|
|
94
160
|
```html
|
|
95
161
|
<libs_ui-components-inputs-input
|
|
96
162
|
[tagInput]="'textarea'"
|
|
97
163
|
[(value)]="textareaValue"
|
|
98
|
-
[
|
|
164
|
+
[defaultHeight]="80"
|
|
165
|
+
[minHeightTextArea]="80"
|
|
99
166
|
[maxHeightTextArea]="300"
|
|
167
|
+
[maxLength]="500"
|
|
100
168
|
[showCount]="true"
|
|
101
|
-
[
|
|
169
|
+
[placeholder]="'Nhập mô tả...'"
|
|
170
|
+
(outChange)="handlerTextareaChange($event)"
|
|
171
|
+
(outHeightAreaChange)="handlerHeightChange($event)" />
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
```typescript
|
|
175
|
+
protected textareaValue = signal('');
|
|
176
|
+
|
|
177
|
+
handlerTextareaChange(value: string): void {
|
|
178
|
+
// value là chuỗi text
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
handlerHeightChange(data: { isChange: boolean; height: number }): void {
|
|
182
|
+
// data.height là chiều cao mới của textarea
|
|
183
|
+
}
|
|
102
184
|
```
|
|
103
185
|
|
|
104
|
-
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
### Password Input
|
|
105
189
|
|
|
106
190
|
```html
|
|
107
191
|
<libs_ui-components-inputs-input
|
|
108
|
-
[
|
|
109
|
-
[(value)]="
|
|
110
|
-
[
|
|
111
|
-
[
|
|
192
|
+
[typeInput]="'password'"
|
|
193
|
+
[(value)]="passwordValue"
|
|
194
|
+
[resetAutoCompletePassword]="true"
|
|
195
|
+
[placeholder]="'Nhập mật khẩu'"
|
|
196
|
+
(outChange)="handlerPasswordChange($event)" />
|
|
112
197
|
```
|
|
113
198
|
|
|
114
|
-
|
|
199
|
+
```typescript
|
|
200
|
+
protected passwordValue = signal('');
|
|
201
|
+
|
|
202
|
+
handlerPasswordChange(value: string): void {
|
|
203
|
+
// xử lý password
|
|
204
|
+
}
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
---
|
|
208
|
+
|
|
209
|
+
### Input với Icon Left/Right và Popover
|
|
115
210
|
|
|
116
211
|
```html
|
|
117
212
|
<libs_ui-components-inputs-input
|
|
118
213
|
[(value)]="searchValue"
|
|
119
214
|
[iconLeftClass]="'libs-ui-icon-search'"
|
|
120
215
|
[iconRightClass]="'libs-ui-icon-close'"
|
|
121
|
-
[popoverContentIconLeft]="'
|
|
122
|
-
|
|
123
|
-
|
|
216
|
+
[popoverContentIconLeft]="'Tìm kiếm'"
|
|
217
|
+
[popoverContentIconRight]="'Xóa nội dung'"
|
|
218
|
+
[placeholder]="'Tìm kiếm...'"
|
|
219
|
+
(outChange)="handlerSearchChange($event)"
|
|
220
|
+
(outIconLeft)="handlerIconLeftClick($event)"
|
|
221
|
+
(outIconRight)="handlerIconRightClick($event)" />
|
|
124
222
|
```
|
|
125
223
|
|
|
126
|
-
|
|
224
|
+
```typescript
|
|
225
|
+
protected searchValue = signal('');
|
|
226
|
+
|
|
227
|
+
handlerSearchChange(value: string): void {
|
|
228
|
+
// xử lý tìm kiếm
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
handlerIconLeftClick(eventName: string): void {
|
|
232
|
+
// eventName = 'click'
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
handlerIconRightClick(eventName: string): void {
|
|
236
|
+
this.searchValue.set('');
|
|
237
|
+
}
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
---
|
|
241
|
+
|
|
242
|
+
### External Control qua FunctionsControl
|
|
127
243
|
|
|
128
244
|
```html
|
|
129
245
|
<libs_ui-components-inputs-input
|
|
130
246
|
[(value)]="controlledValue"
|
|
131
|
-
|
|
247
|
+
[placeholder]="'Điều khiển từ bên ngoài'"
|
|
248
|
+
(outFunctionsControl)="handlerFunctionsControl($event)" />
|
|
132
249
|
|
|
133
|
-
<button (click)="
|
|
134
|
-
<button (click)="
|
|
250
|
+
<button (click)="handlerFocusInput()">Focus</button>
|
|
251
|
+
<button (click)="handlerInsertText()">Insert "Hello"</button>
|
|
252
|
+
<button (click)="handlerResetInput()">Reset</button>
|
|
253
|
+
<button (click)="handlerSelectAll()">Select All</button>
|
|
135
254
|
```
|
|
136
255
|
|
|
137
256
|
```typescript
|
|
138
|
-
|
|
257
|
+
import { signal } from '@angular/core';
|
|
258
|
+
import { IInputFunctionControlEvent } from '@libs-ui/components-inputs-input';
|
|
139
259
|
|
|
140
|
-
|
|
260
|
+
protected controlledValue = signal('');
|
|
261
|
+
private functionControl = signal<IInputFunctionControlEvent | null>(null);
|
|
262
|
+
|
|
263
|
+
handlerFunctionsControl(control: IInputFunctionControlEvent): void {
|
|
141
264
|
this.functionControl.set(control);
|
|
142
265
|
}
|
|
143
266
|
|
|
144
|
-
async
|
|
267
|
+
async handlerFocusInput(): Promise<void> {
|
|
145
268
|
await this.functionControl()?.focus();
|
|
146
269
|
}
|
|
147
270
|
|
|
148
|
-
async
|
|
149
|
-
await this.functionControl()?.insertContent(
|
|
271
|
+
async handlerInsertText(): Promise<void> {
|
|
272
|
+
await this.functionControl()?.insertContent('Hello');
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
async handlerResetInput(): Promise<void> {
|
|
276
|
+
await this.functionControl()?.resetValue();
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
async handlerSelectAll(): Promise<void> {
|
|
280
|
+
await this.functionControl()?.selectAllContent();
|
|
150
281
|
}
|
|
151
282
|
```
|
|
152
283
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
###
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
| `[classContainerBottomInput]` | `string` | `' '` | Class cho container dưới input |
|
|
169
|
-
| `[classContainerInput]` | `string` | `'w-full'` | Class cho container input |
|
|
170
|
-
| `[classInclude]` | `string` | `' w-full '` | Class bao ngoài component |
|
|
171
|
-
| `[dataType]` | `TYPE_DATA_TYPE_INPUT` | `'string'` | Data type: string, int, float, bigint |
|
|
172
|
-
| `[defaultHeight]` | `number` | `32` | Chiều cao mặc định |
|
|
173
|
-
| `[disable]` | `boolean` | `false` | Disable mode |
|
|
174
|
-
| `[emitEmptyInDataTypeNumber]` | `boolean` | `false` | Emit empty string khi xoá hết number |
|
|
175
|
-
| `[fixedFloat]` | `number` | `undefined` | Số chữ số thập phân |
|
|
176
|
-
| `[focusInput]` | `boolean` | `false` | Auto focus input |
|
|
177
|
-
| `[focusTimeOut]` | `number` | `600` | Delay time cho focus method |
|
|
178
|
-
| `[iconLeftClass]` | `string` | `''` | Class cho icon trái |
|
|
179
|
-
| `[iconRightClass]` | `string` | `undefined` | Class cho icon phải |
|
|
180
|
-
| `[iframeTextareaCustomStyle]` | `IIframeTextareaCustomStyle` | `undefined` | Custom style cho iframe textarea |
|
|
181
|
-
| `[ignoreBlockInputMaxValue]` | `boolean` | `undefined` | Không chặn nhập quá max value |
|
|
182
|
-
| `[ignoreStopPropagationEvent]` | `boolean` | `undefined` | Không chặn propagation event |
|
|
183
|
-
| `[ignoreWidthInput100]` | `boolean` | `undefined` | Không set width 100% |
|
|
184
|
-
| `[keepPlaceholderOnly]` | `boolean` | `false` | Chỉ giữ placeholder (ẩn value) |
|
|
185
|
-
| `[keepZeroInTypeInt]` | `boolean` | `false` | Giữ số 0 ở đầu (int) |
|
|
186
|
-
| `[maxHeightTextArea]` | `number` | `250` | Max height cho textarea |
|
|
187
|
-
| `[maxLength]` | `number` | `undefined` | Max character length |
|
|
188
|
-
| `[maxLengthNumberCount]` | `number` | `undefined` | Max length cho phần số (bigint) |
|
|
189
|
-
| `[minHeightTextArea]` | `number` | `undefined` | Min height cho textarea |
|
|
190
|
-
| `[minValueNumber]` | `number` | `undefined` | Min value cho number input |
|
|
191
|
-
| `[maxValueNumber]` | `number` | `undefined` | Max value cho number input |
|
|
192
|
-
| `[noBorder]` | `boolean` | `false` | Ẩn border |
|
|
193
|
-
| `[onlyAcceptNegativeValue]` | `boolean` | `false` | Chỉ chấp nhận số âm |
|
|
194
|
-
| `[placeholder]` | `string` | `' '` | Placeholder text |
|
|
195
|
-
| `[popoverContentIconLeft]` | `string` | `''` | Popover content icon trái |
|
|
196
|
-
| `[popoverContentIconRight]` | `string` | `''` | Popover content icon phải |
|
|
197
|
-
| `[readonly]` | `boolean` | `false` | Readonly mode |
|
|
198
|
-
| `[resetAutoCompletePassword]` | `boolean` | `false` | Reset autocomplete cho password |
|
|
199
|
-
| `[resize]` | `TYPE_INPUT_RESIZE_MODE` | `'vertical'` | Resize mode |
|
|
200
|
-
| `[selectAllTimeOut]` | `number` | `600` | Delay time cho selectAll |
|
|
201
|
-
| `[setIconRightColorSameColorDisableReadOnly]` | `boolean` | `false` | Icon phải cùng màu disable text |
|
|
202
|
-
| `[showCount]` | `boolean` | `false` | Hiển thị character count |
|
|
203
|
-
| `[tabInsertContentTagInput]` | `boolean` | `false` | Cho phép dùng Tab để insert |
|
|
204
|
-
| `[tagInput]` | `TYPE_TAG_INPUT` | `'input'` | Tag type: input, textarea, iframe-textarea |
|
|
205
|
-
| `[templateLeftBottomInput]` | `TemplateRef<TYPE_TEMPLATE_REF>` | `undefined` | Template custom dưới trái |
|
|
206
|
-
| `[templateRightBottomInput]` | `TemplateRef<TYPE_TEMPLATE_REF>` | `undefined` | Template custom dưới phải |
|
|
207
|
-
| `[textAreaEnterNotNewLine]` | `boolean` | `false` | Enter không xuống dòng trong textarea |
|
|
208
|
-
| `[typeInput]` | `TYPE_INPUT` | `'text'` | Input type: text, number, password |
|
|
209
|
-
| `[useColorModeExist]` | `boolean` | `false` | Sử dụng màu sắc theo mode của hệ thống |
|
|
210
|
-
| `[value]` | `string \| number` | `''` | Input value (model binding) |
|
|
211
|
-
| `[valueUpDownNumber]` | `number` | `undefined` | Bước nhảy cho nút tăng giảm |
|
|
212
|
-
| `[zIndexPopoverContent]` | `number` | `10` | Z-index cho popover content |
|
|
213
|
-
|
|
214
|
-
**Note**: Component có 50+ inputs. Xem demo tại `/inputs/input` để biết chi tiết.
|
|
215
|
-
|
|
216
|
-
### Outputs
|
|
217
|
-
|
|
218
|
-
| Property | Type | Description |
|
|
219
|
-
| -------------------------------- | ------------------------------------------ | --------------------------------------------- |
|
|
220
|
-
| Property | Type | Description |
|
|
221
|
-
| -------------------------------- | ------------------------------------------ | -------------------------------------------- |
|
|
222
|
-
| `(outChange)` | `any` | Emit khi value thay đổi (two-way binding) |
|
|
223
|
-
| `(outChangeValueByButtonUpDown)` | `void` | Emit khi click button up/down |
|
|
224
|
-
| `(outEnterEvent)` | `IEvent` | Emit khi nhấn Enter |
|
|
225
|
-
| `(outFileDrop)` | `File` | Emit khi drop single file |
|
|
226
|
-
| `(outFilesDrop)` | `Array<File>` | Emit khi drop multiple files |
|
|
227
|
-
| `(outFocusAndBlurEvent)` | `IFocusAndBlurEvent` | Emit khi focus/blur |
|
|
228
|
-
| `(outFunctionsControl)` | `IInputFunctionControlEvent` | Emit function controls instance |
|
|
229
|
-
| `(outHeightAreaChange)` | `{ isChange: boolean; height: number; }` | Emit khi height textarea thay đổi auto-resize |
|
|
230
|
-
| `(outIconLeft)` | `string` | Emit khi click icon left |
|
|
231
|
-
| `(outIconRight)` | `string` | Emit khi click icon right |
|
|
232
|
-
| `(outInputEvent)` | `IEvent` | Emit pure input event (native) |
|
|
233
|
-
|
|
234
|
-
### FunctionsControl Methods
|
|
235
|
-
|
|
236
|
-
| Method | Description |
|
|
237
|
-
| ---------------------------- | ------------------------- |
|
|
238
|
-
| `focus(emitEvent?: boolean)` | Focus vào input |
|
|
239
|
-
| `blur(emitEvent?: boolean)` | Blur khỏi input |
|
|
240
|
-
| `insertContent(data)` | Insert content vào cursor |
|
|
241
|
-
| `resetValue()` | Reset value về empty |
|
|
242
|
-
| `getElementValue()` | Lấy value từ element |
|
|
243
|
-
| `selectAllContent()` | Select all content |
|
|
244
|
-
|
|
245
|
-
## Types
|
|
284
|
+
---
|
|
285
|
+
|
|
286
|
+
### IFrame Textarea với Custom Style
|
|
287
|
+
|
|
288
|
+
```html
|
|
289
|
+
<libs_ui-components-inputs-input
|
|
290
|
+
[tagInput]="'iframe-textarea'"
|
|
291
|
+
[(value)]="iframeValue"
|
|
292
|
+
[iframeTextareaCustomStyle]="iframeStyle"
|
|
293
|
+
[defaultHeight]="120"
|
|
294
|
+
[maxHeightTextArea]="400"
|
|
295
|
+
[placeholder]="'Nhập nội dung (cô lập CSS)'"
|
|
296
|
+
(outChange)="handlerIframeChange($event)"
|
|
297
|
+
(outFunctionsControl)="handlerIframeFunctionsControl($event)" />
|
|
298
|
+
```
|
|
246
299
|
|
|
247
300
|
```typescript
|
|
248
|
-
|
|
249
|
-
|
|
301
|
+
import { IIframeTextareaCustomStyle, IInputFunctionControlEvent } from '@libs-ui/components-inputs-input';
|
|
302
|
+
|
|
303
|
+
protected iframeValue = signal('');
|
|
304
|
+
protected iframeStyle: IIframeTextareaCustomStyle = {
|
|
305
|
+
fontSize: '14px',
|
|
306
|
+
lineHeight: '1.6',
|
|
307
|
+
padding: '8px 12px',
|
|
308
|
+
color: '#333333',
|
|
309
|
+
backgroundColor: '#ffffff',
|
|
310
|
+
borderColor: '#e2e8f0',
|
|
311
|
+
borderRadius: '6px',
|
|
312
|
+
};
|
|
313
|
+
|
|
314
|
+
handlerIframeChange(value: string): void {
|
|
315
|
+
// value là nội dung textarea bên trong iframe
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
handlerIframeFunctionsControl(control: IInputFunctionControlEvent): void {
|
|
319
|
+
// lưu control để điều khiển từ bên ngoài
|
|
320
|
+
}
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
---
|
|
324
|
+
|
|
325
|
+
### Number Input với Nút Up/Down
|
|
326
|
+
|
|
327
|
+
```html
|
|
328
|
+
<libs_ui-components-inputs-input
|
|
329
|
+
[dataType]="'int'"
|
|
330
|
+
[(value)]="stepValue"
|
|
331
|
+
[minValueNumber]="0"
|
|
332
|
+
[maxValueNumber]="10"
|
|
333
|
+
[valueUpDownNumber]="1"
|
|
334
|
+
[placeholder]="'0'"
|
|
335
|
+
(outChange)="handlerStepChange($event)"
|
|
336
|
+
(outChangeValueByButtonUpDown)="handlerUpDownClick()" />
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
```typescript
|
|
340
|
+
protected stepValue = signal<number>(0);
|
|
341
|
+
|
|
342
|
+
handlerStepChange(value: number): void {
|
|
343
|
+
// value thay đổi
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
handlerUpDownClick(): void {
|
|
347
|
+
// được gọi khi click nút tăng/giảm
|
|
348
|
+
}
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
---
|
|
352
|
+
|
|
353
|
+
### Textarea không xuống dòng khi Enter
|
|
354
|
+
|
|
355
|
+
```html
|
|
356
|
+
<libs_ui-components-inputs-input
|
|
357
|
+
[tagInput]="'textarea'"
|
|
358
|
+
[(value)]="singleLineValue"
|
|
359
|
+
[textAreaEnterNotNewLine]="true"
|
|
360
|
+
[placeholder]="'Enter để submit, Shift+Enter xuống dòng'"
|
|
361
|
+
(outChange)="handlerChange($event)"
|
|
362
|
+
(outEnterEvent)="handlerEnter($event)" />
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
```typescript
|
|
366
|
+
import { IEvent } from '@libs-ui/interfaces-types';
|
|
367
|
+
|
|
368
|
+
protected singleLineValue = signal('');
|
|
369
|
+
|
|
370
|
+
handlerChange(value: string): void {
|
|
371
|
+
// xử lý thay đổi
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
handlerEnter(event: IEvent): void {
|
|
375
|
+
event.stopPropagation();
|
|
376
|
+
// xử lý submit khi nhấn Enter
|
|
377
|
+
}
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
---
|
|
381
|
+
|
|
382
|
+
### Drag & Drop File vào Input
|
|
383
|
+
|
|
384
|
+
```html
|
|
385
|
+
<libs_ui-components-inputs-input
|
|
386
|
+
[(value)]="fileDropValue"
|
|
387
|
+
[placeholder]="'Kéo file vào đây hoặc nhập text'"
|
|
388
|
+
(outChange)="handlerChange($event)"
|
|
389
|
+
(outFilesDrop)="handlerFilesDrop($event)"
|
|
390
|
+
(outFileDrop)="handlerFileDrop($event)" />
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
```typescript
|
|
394
|
+
protected fileDropValue = signal('');
|
|
395
|
+
|
|
396
|
+
handlerChange(value: string): void {
|
|
397
|
+
// xử lý text thay đổi
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
handlerFilesDrop(files: File[]): void {
|
|
401
|
+
// xử lý nhiều file drop
|
|
402
|
+
files.forEach(file => console.log(file.name));
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
handlerFileDrop(file: File): void {
|
|
406
|
+
// xử lý từng file riêng lẻ
|
|
407
|
+
}
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
## @Input()
|
|
411
|
+
|
|
412
|
+
| Input | Type | Default | Mô tả | Ví dụ |
|
|
413
|
+
|---|---|---|---|---|
|
|
414
|
+
| `[acceptNegativeValue]` | `boolean` | `false` | Cho phép nhập giá trị âm | `[acceptNegativeValue]="true"` |
|
|
415
|
+
| `[acceptOnlyClickIcon]` | `boolean` | `false` | Cho phép click icon kể cả khi disable/readonly | `[acceptOnlyClickIcon]="true"` |
|
|
416
|
+
| `[autoAddZeroLessThan10InTypeInt]` | `boolean` | `false` | Tự động thêm số 0 trước nếu giá trị < 10 (dataType=int) | `[autoAddZeroLessThan10InTypeInt]="true"` |
|
|
417
|
+
| `[autoRemoveEmoji]` | `boolean` | `false` | Tự động loại bỏ emoji khỏi chuỗi nhập | `[autoRemoveEmoji]="true"` |
|
|
418
|
+
| `[backgroundNone]` | `boolean` | `false` | Làm trong suốt background của input | `[backgroundNone]="true"` |
|
|
419
|
+
| `[blurTimeOut]` | `number` | `32` | Delay (ms) trước khi blur được thực thi | `[blurTimeOut]="50"` |
|
|
420
|
+
| `[borderError]` | `boolean` | `false` | Hiển thị border màu đỏ báo lỗi | `[borderError]="hasError()"` |
|
|
421
|
+
| `[classContainerBottomInput]` | `string` | `' '` | CSS class cho container bên dưới input | `[classContainerBottomInput]="'flex gap-2'"` |
|
|
422
|
+
| `[classContainerInput]` | `string` | `'w-full'` | CSS class cho container bọc input | `[classContainerInput]="'w-64'"` |
|
|
423
|
+
| `[classInclude]` | `string` | `' w-full '` | CSS class bổ sung cho element input | `[classInclude]="'text-right'"` |
|
|
424
|
+
| `[dataType]` | `TYPE_DATA_TYPE_INPUT` | `'string'` | Kiểu dữ liệu: `'string'` \| `'int'` \| `'float'` \| `'bigint'` | `[dataType]="'int'"` |
|
|
425
|
+
| `[defaultHeight]` | `number` | `32` | Chiều cao mặc định (px) | `[defaultHeight]="40"` |
|
|
426
|
+
| `[disable]` | `boolean` | `false` | Vô hiệu hóa input | `[disable]="isLoading()"` |
|
|
427
|
+
| `[emitEmptyInDataTypeNumber]` | `boolean` | `false` | Emit `undefined` khi xóa hết giá trị number | `[emitEmptyInDataTypeNumber]="true"` |
|
|
428
|
+
| `[(fixedFloat)]` | `number` | `undefined` | Số chữ số thập phân tối đa (dùng với float/bigint) | `[(fixedFloat)]="2"` |
|
|
429
|
+
| `[focusInput]` | `boolean` | `false` | Tự động focus input khi render | `[focusInput]="true"` |
|
|
430
|
+
| `[focusTimeOut]` | `number` | `600` | Delay (ms) trước khi focus được thực thi | `[focusTimeOut]="300"` |
|
|
431
|
+
| `[iconLeftClass]` | `string` | `''` | CSS class cho icon bên trái | `[iconLeftClass]="'libs-ui-icon-search'"` |
|
|
432
|
+
| `[iconRightClass]` | `string` | `undefined` | CSS class cho icon bên phải | `[iconRightClass]="'libs-ui-icon-close'"` |
|
|
433
|
+
| `[iframeTextareaCustomStyle]` | `IIframeTextareaCustomStyle` | `undefined` | Custom style cho nội dung bên trong iframe-textarea | `[iframeTextareaCustomStyle]="myStyle"` |
|
|
434
|
+
| `[ignoreBlockInputMaxValue]` | `boolean` | `undefined` | Không chặn nhập khi vượt quá maxValueNumber | `[ignoreBlockInputMaxValue]="true"` |
|
|
435
|
+
| `[ignoreStopPropagationEvent]` | `boolean` | `undefined` | Không gọi stopPropagation trên sự kiện native | `[ignoreStopPropagationEvent]="true"` |
|
|
436
|
+
| `[ignoreWidthInput100]` | `boolean` | `undefined` | Không áp dụng `w-full` cho element input | `[ignoreWidthInput100]="true"` |
|
|
437
|
+
| `[keepPlaceholderOnly]` | `boolean` | `false` | Chỉ hiển thị placeholder, ẩn giá trị thực | `[keepPlaceholderOnly]="true"` |
|
|
438
|
+
| `[keepZeroInTypeInt]` | `boolean` | `false` | Giữ số 0 ở đầu khi nhập (dataType=int) | `[keepZeroInTypeInt]="true"` |
|
|
439
|
+
| `[(maxLength)]` | `number` | `undefined` | Số ký tự tối đa được nhập | `[(maxLength)]="100"` |
|
|
440
|
+
| `[(maxLengthNumberCount)]` | `number` | `undefined` | Số chữ số tối đa phần nguyên (dataType=bigint) | `[(maxLengthNumberCount)]="19"` |
|
|
441
|
+
| `[maxHeightTextArea]` | `number` | `250` | Chiều cao tối đa textarea (px) | `[maxHeightTextArea]="400"` |
|
|
442
|
+
| `[(maxValueNumber)]` | `number` | `undefined` | Giá trị tối đa cho number input | `[(maxValueNumber)]="100"` |
|
|
443
|
+
| `[minHeightTextArea]` | `number` | `undefined` | Chiều cao tối thiểu textarea (px) | `[minHeightTextArea]="80"` |
|
|
444
|
+
| `[(minValueNumber)]` | `number` | `undefined` | Giá trị tối thiểu cho number input | `[(minValueNumber)]="0"` |
|
|
445
|
+
| `[modeInput]` | `TYPE_MODE_INPUT` | `'text'` | inputmode cho mobile keyboard: `'none'` \| `'text'` \| `'tel'` \| `'url'` \| `'email'` \| `'numeric'` \| `'decimal'` | `[modeInput]="'numeric'"` |
|
|
446
|
+
| `[noBorder]` | `boolean` | `false` | Ẩn border của input | `[noBorder]="true"` |
|
|
447
|
+
| `[onlyAcceptNegativeValue]` | `boolean` | `false` | Chỉ chấp nhận số âm (tự động set acceptNegativeValue=true) | `[onlyAcceptNegativeValue]="true"` |
|
|
448
|
+
| `[placeholder]` | `string` | `' '` | Placeholder text (hỗ trợ i18n key) | `[placeholder]="'i18n_enter_value'"` |
|
|
449
|
+
| `[popoverContentIconLeft]` | `string` | `''` | Nội dung popover khi hover icon trái | `[popoverContentIconLeft]="'Tìm kiếm'"` |
|
|
450
|
+
| `[popoverContentIconRight]` | `string` | `''` | Nội dung popover khi hover icon phải | `[popoverContentIconRight]="'Xóa'"` |
|
|
451
|
+
| `[readonly]` | `boolean` | `false` | Chỉ đọc, không cho phép chỉnh sửa | `[readonly]="isViewing()"` |
|
|
452
|
+
| `[resetAutoCompletePassword]` | `boolean` | `false` | Tắt autocomplete của browser (dùng cho password) | `[resetAutoCompletePassword]="true"` |
|
|
453
|
+
| `[resize]` | `TYPE_INPUT_RESIZE_MODE` | `'vertical'` | Chế độ resize textarea: `'auto'` \| `'vertical'` \| `'horizontal'` \| `'none'` | `[resize]="'none'"` |
|
|
454
|
+
| `[selectAllTimeOut]` | `number` | `600` | Delay (ms) trước khi selectAll được thực thi | `[selectAllTimeOut]="300"` |
|
|
455
|
+
| `[setIconRightColorSameColorDisableReadOnly]` | `boolean` | `false` | Icon phải có màu giống màu text disable/readonly | `[setIconRightColorSameColorDisableReadOnly]="true"` |
|
|
456
|
+
| `[showCount]` | `boolean` | `false` | Hiển thị số ký tự đã nhập (dataType=string) | `[showCount]="true"` |
|
|
457
|
+
| `[tabInsertContentTagInput]` | `boolean` | `false` | Cho phép dùng phím Tab để chèn ký tự tab vào input | `[tabInsertContentTagInput]="true"` |
|
|
458
|
+
| `[tagInput]` | `TYPE_TAG_INPUT` | `'input'` | Loại element: `'input'` \| `'textarea'` \| `'iframe-textarea'` | `[tagInput]="'textarea'"` |
|
|
459
|
+
| `[templateLeftBottomInput]` | `TemplateRef` | `undefined` | Template tùy chỉnh ở góc dưới trái | `[templateLeftBottomInput]="myLeftTpl"` |
|
|
460
|
+
| `[templateRightBottomInput]` | `TemplateRef` | `undefined` | Template tùy chỉnh ở góc dưới phải | `[templateRightBottomInput]="myRightTpl"` |
|
|
461
|
+
| `[textAreaEnterNotNewLine]` | `boolean` | `false` | Enter không xuống dòng trong textarea (dùng Shift+Enter để xuống dòng) | `[textAreaEnterNotNewLine]="true"` |
|
|
462
|
+
| `[typeInput]` | `TYPE_INPUT` | `'text'` | HTML input type: `'text'` \| `'number'` \| `'password'` | `[typeInput]="'password'"` |
|
|
463
|
+
| `[useColorModeExist]` | `boolean` | `false` | Áp dụng màu text theo color mode của hệ thống | `[useColorModeExist]="true"` |
|
|
464
|
+
| `[(value)]` | `string \| number` | `''` | Giá trị input (two-way binding qua model) | `[(value)]="myValue"` |
|
|
465
|
+
| `[valueUpDownNumber]` | `number` | `undefined` | Bước nhảy mỗi lần nhấn nút tăng/giảm | `[valueUpDownNumber]="5"` |
|
|
466
|
+
| `[zIndexPopoverContent]` | `number` | `10` | Z-index của popover content | `[zIndexPopoverContent]="100"` |
|
|
467
|
+
|
|
468
|
+
## @Output()
|
|
469
|
+
|
|
470
|
+
| Output | Type | Mô tả | Handler TS | Binding HTML |
|
|
471
|
+
|---|---|---|---|---|
|
|
472
|
+
| `(outChange)` | `string \| number \| undefined` | Emit khi value thay đổi, đã được parse theo `dataType` | `handlerChange(value: string \| number): void { /* xử lý */ }` | `(outChange)="handlerChange($event)"` |
|
|
473
|
+
| `(outChangeValueByButtonUpDown)` | `void` | Emit khi người dùng click nút tăng hoặc giảm | `handlerUpDownClick(): void { /* xử lý */ }` | `(outChangeValueByButtonUpDown)="handlerUpDownClick()"` |
|
|
474
|
+
| `(outEnterEvent)` | `IEvent` | Emit khi nhấn phím Enter (trong textarea nếu `textAreaEnterNotNewLine=true` thì chỉ Enter không Shift) | `handlerEnter(event: IEvent): void { event.stopPropagation(); /* xử lý submit */ }` | `(outEnterEvent)="handlerEnter($event)"` |
|
|
475
|
+
| `(outFileDrop)` | `File` | Emit từng file riêng lẻ khi drop hoặc paste file vào input | `handlerFileDrop(file: File): void { event.stopPropagation(); /* xử lý file */ }` | `(outFileDrop)="handlerFileDrop($event)"` |
|
|
476
|
+
| `(outFilesDrop)` | `Array<File>` | Emit toàn bộ danh sách file khi drop hoặc paste vào input | `handlerFilesDrop(files: File[]): void { event.stopPropagation(); /* xử lý danh sách */ }` | `(outFilesDrop)="handlerFilesDrop($event)"` |
|
|
477
|
+
| `(outFocusAndBlurEvent)` | `IFocusAndBlurEvent` | Emit khi input được focus hoặc blur, kèm `name: 'focus' \| 'blur'` | `handlerFocusBlur(e: IFocusAndBlurEvent): void { e.event.stopPropagation(); /* xử lý */ }` | `(outFocusAndBlurEvent)="handlerFocusBlur($event)"` |
|
|
478
|
+
| `(outFunctionsControl)` | `IInputFunctionControlEvent` | Emit API điều khiển: focus, blur, insert, reset, selectAll | `handlerFunctionsControl(ctrl: IInputFunctionControlEvent): void { this.ctrl.set(ctrl); }` | `(outFunctionsControl)="handlerFunctionsControl($event)"` |
|
|
479
|
+
| `(outHeightAreaChange)` | `{ isChange: boolean; height: number }` | Emit khi chiều cao textarea thay đổi do auto-resize | `handlerHeightChange(data: { isChange: boolean; height: number }): void { /* xử lý */ }` | `(outHeightAreaChange)="handlerHeightChange($event)"` |
|
|
480
|
+
| `(outIconLeft)` | `string` | Emit khi click icon trái, giá trị là tên event (`'click'`) | `handlerIconLeft(eventName: string): void { eventName; /* 'click' */ }` | `(outIconLeft)="handlerIconLeft($event)"` |
|
|
481
|
+
| `(outIconRight)` | `string` | Emit khi click icon phải, giá trị là tên event (`'click'`) | `handlerIconRight(eventName: string): void { eventName; /* 'click' */ }` | `(outIconRight)="handlerIconRight($event)"` |
|
|
482
|
+
| `(outInputEvent)` | `IEvent` | Emit native input event gốc (mỗi lần DOM input event xảy ra) | `handlerInputEvent(e: IEvent): void { e.stopPropagation(); /* xử lý native event */ }` | `(outInputEvent)="handlerInputEvent($event)"` |
|
|
483
|
+
|
|
484
|
+
## FunctionsControl API
|
|
485
|
+
|
|
486
|
+
Nhận instance `IInputFunctionControlEvent` qua output `(outFunctionsControl)`. Tất cả methods là async.
|
|
487
|
+
|
|
488
|
+
| Method | Signature | Mô tả |
|
|
489
|
+
|---|---|---|
|
|
490
|
+
| `focus` | `(emitEvent?: boolean) => Promise<void>` | Focus vào input. Nếu `emitEvent=true` thì emit `outFocusAndBlurEvent` |
|
|
491
|
+
| `blur` | `(emitEvent?: boolean) => Promise<void>` | Blur khỏi input. Nếu `emitEvent=true` thì emit `outFocusAndBlurEvent` |
|
|
492
|
+
| `insertContent` | `(data: string \| number) => Promise<void>` | Chèn nội dung vào vị trí con trỏ hiện tại |
|
|
493
|
+
| `resetValue` | `() => Promise<void>` | Reset value về chuỗi rỗng và emit `outChange` |
|
|
494
|
+
| `getElementValue` | `() => Promise<string> \| undefined` | Lấy giá trị raw từ DOM element |
|
|
495
|
+
| `checkAndDisableUpDownButton` | `(value: number) => Promise<void>` | Kiểm tra và cập nhật trạng thái disable của nút tăng/giảm |
|
|
496
|
+
| `selectAllContent` | `() => Promise<void>` | Chọn toàn bộ nội dung trong input |
|
|
497
|
+
|
|
498
|
+
## Types & Interfaces
|
|
499
|
+
|
|
500
|
+
```typescript
|
|
501
|
+
import {
|
|
502
|
+
TYPE_INPUT,
|
|
503
|
+
TYPE_DATA_TYPE_INPUT,
|
|
504
|
+
TYPE_TAG_INPUT,
|
|
505
|
+
TYPE_MODE_INPUT,
|
|
506
|
+
TYPE_INPUT_RESIZE_MODE,
|
|
507
|
+
IInputFunctionControlEvent,
|
|
508
|
+
IFocusAndBlurEvent,
|
|
509
|
+
IIframeTextareaCustomStyle,
|
|
510
|
+
} from '@libs-ui/components-inputs-input';
|
|
511
|
+
|
|
512
|
+
// Loại HTML element
|
|
250
513
|
type TYPE_TAG_INPUT = 'input' | 'textarea' | 'iframe-textarea';
|
|
251
|
-
type TYPE_INPUT_RESIZE_MODE = 'auto' | 'vertical' | 'horizontal' | 'none';
|
|
252
514
|
|
|
515
|
+
// Kiểu dữ liệu
|
|
516
|
+
type TYPE_DATA_TYPE_INPUT = 'string' | 'int' | 'float' | 'bigint';
|
|
517
|
+
|
|
518
|
+
// HTML input type attribute
|
|
519
|
+
type TYPE_INPUT = 'text' | 'number' | 'password';
|
|
520
|
+
|
|
521
|
+
// inputmode attribute (mobile keyboard)
|
|
522
|
+
type TYPE_MODE_INPUT = 'none' | 'text' | 'tel' | 'url' | 'email' | 'numeric' | 'decimal';
|
|
523
|
+
|
|
524
|
+
// Chế độ resize textarea
|
|
525
|
+
type TYPE_INPUT_RESIZE_MODE = 'auto' | 'vertical' | 'horizontal' | 'none' | undefined;
|
|
526
|
+
|
|
527
|
+
// API điều khiển từ component cha
|
|
253
528
|
interface IInputFunctionControlEvent {
|
|
254
529
|
focus: (emitEvent?: boolean) => Promise<void>;
|
|
255
530
|
blur: (emitEvent?: boolean) => Promise<void>;
|
|
256
531
|
insertContent: (data: string | number) => Promise<void>;
|
|
257
532
|
resetValue: () => Promise<void>;
|
|
258
|
-
getElementValue: () => Promise<
|
|
533
|
+
getElementValue: () => Promise<string> | undefined;
|
|
534
|
+
checkAndDisableUpDownButton: (value: number) => Promise<void>;
|
|
259
535
|
selectAllContent: () => Promise<void>;
|
|
260
536
|
}
|
|
261
537
|
|
|
538
|
+
// Event focus/blur
|
|
539
|
+
interface IFocusAndBlurEvent {
|
|
540
|
+
name: 'focus' | 'blur';
|
|
541
|
+
event: Event;
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
// Custom style cho iframe-textarea
|
|
262
545
|
interface IIframeTextareaCustomStyle {
|
|
263
546
|
borderRadius?: string;
|
|
264
547
|
borderColor?: string;
|
|
@@ -271,6 +554,22 @@ interface IIframeTextareaCustomStyle {
|
|
|
271
554
|
}
|
|
272
555
|
```
|
|
273
556
|
|
|
557
|
+
## Lưu ý quan trọng
|
|
558
|
+
|
|
559
|
+
⚠️ **Number Formatting theo Locale**: Component tự động format number theo ngôn ngữ hiện tại. Tiếng Việt (VI) dùng dấu `.` phân cách nghìn và `,` phân cách thập phân. Tiếng Anh (EN) dùng `,` phân cách nghìn và `.` phân cách thập phân.
|
|
560
|
+
|
|
561
|
+
⚠️ **Giới hạn độ chính xác số**: `int` tối đa 16-17 chữ số, `float` tối đa 15 chữ số phần nguyên + phần thập phân, `bigint` cấu hình được qua `maxLengthNumberCount` (default 19) và `fixedFloat` (default 4).
|
|
562
|
+
|
|
563
|
+
⚠️ **value là model (two-way binding)**: Dùng `[(value)]="mySignal"` để binding hai chiều. Output `(outChange)` emit giá trị đã được parse theo `dataType` — với `bigint` trả về `string`, các loại khác trả về `number` hoặc `string`.
|
|
564
|
+
|
|
565
|
+
⚠️ **iframe-textarea CSS isolation**: Khi dùng `tagInput="iframe-textarea"`, content được render bên trong `<iframe>` — CSS của trang cha không áp dụng vào bên trong. Dùng `[iframeTextareaCustomStyle]` để tùy chỉnh giao diện bên trong iframe (fontSize, padding, color, borderColor...).
|
|
566
|
+
|
|
567
|
+
⚠️ **FunctionsControl timing**: Output `(outFunctionsControl)` emit sau khi DOM element được khởi tạo xong. Lưu instance vào signal để dùng sau: `private ctrl = signal<IInputFunctionControlEvent | null>(null)`.
|
|
568
|
+
|
|
569
|
+
⚠️ **textAreaEnterNotNewLine với Shift+Enter**: Khi `[textAreaEnterNotNewLine]="true"`, nhấn `Enter` không xuống dòng và emit `outEnterEvent`. Dùng `Shift+Enter` để xuống dòng bình thường.
|
|
570
|
+
|
|
571
|
+
⚠️ **emitEmptyInDataTypeNumber**: Mặc định khi xóa hết giá trị number, component emit `0`. Bật `[emitEmptyInDataTypeNumber]="true"` để emit `undefined` thay vì `0`.
|
|
572
|
+
|
|
274
573
|
## Demo
|
|
275
574
|
|
|
276
575
|
```bash
|
|
@@ -278,7 +577,3 @@ npx nx serve core-ui
|
|
|
278
577
|
```
|
|
279
578
|
|
|
280
579
|
Truy cập: `http://localhost:4500/inputs/input`
|
|
281
|
-
|
|
282
|
-
## License
|
|
283
|
-
|
|
284
|
-
MIT
|