ngx-digits-only 1.0.3 → 1.1.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 +382 -52
- package/fesm2022/ngx-digits-only.mjs +105 -56
- package/fesm2022/ngx-digits-only.mjs.map +1 -1
- package/package.json +1 -1
- package/types/ngx-digits-only.d.ts +43 -13
package/README.md
CHANGED
|
@@ -1,19 +1,16 @@
|
|
|
1
1
|
# ngx-digits-only
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A dependency-free, standalone Angular directive for smart numeric inputs — digit filtering, formatting, and validation without pulling in a full masking library like `ngx-mask`.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## What does it do?
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
- Implements `ControlValueAccessor` and `Validator` — works natively with Reactive Forms and Template-driven forms
|
|
15
|
-
- Standalone directive — no NgModule required
|
|
16
|
-
- Zero runtime dependencies
|
|
7
|
+
Turns any `<input>` into a smart numeric field:
|
|
8
|
+
|
|
9
|
+
- **Blocks** letters, symbols, and anything that isn't a digit — on every keystroke and paste
|
|
10
|
+
- **Formats** the display with thousands separators, prefix, suffix, and pattern masks
|
|
11
|
+
- **Strips** all display decoration before sending the value to your model
|
|
12
|
+
- **Validates** min, max, maxLength, and pattern completeness automatically
|
|
13
|
+
- **Converts** Arabic / Persian digits to Western digits silently
|
|
17
14
|
|
|
18
15
|
## Installation
|
|
19
16
|
|
|
@@ -21,68 +18,401 @@ Dependency-free Angular directive for numeric-only inputs — a lightweight alte
|
|
|
21
18
|
npm install ngx-digits-only
|
|
22
19
|
```
|
|
23
20
|
|
|
24
|
-
##
|
|
21
|
+
## Quick start
|
|
25
22
|
|
|
26
|
-
|
|
23
|
+
This is a **standalone directive** — no module to import, just the directive itself.
|
|
27
24
|
|
|
28
25
|
```typescript
|
|
29
26
|
import { Component } from '@angular/core';
|
|
30
27
|
import { ReactiveFormsModule } from '@angular/forms';
|
|
31
|
-
import { DigitsOnlyDirective } from 'digits-only';
|
|
28
|
+
import { DigitsOnlyDirective } from 'ngx-digits-only';
|
|
32
29
|
|
|
33
30
|
@Component({
|
|
34
|
-
selector: 'app-example',
|
|
35
31
|
standalone: true,
|
|
36
|
-
imports: [
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
[decimalPlaces]="2"
|
|
42
|
-
[allowNegative]="false"
|
|
43
|
-
[thousandsSeparator]="true"
|
|
44
|
-
[min]="0"
|
|
45
|
-
[max]="1000000"
|
|
46
|
-
[formControl]="amountControl"
|
|
47
|
-
/>
|
|
48
|
-
`
|
|
32
|
+
imports: [
|
|
33
|
+
ReactiveFormsModule, // or FormsModule if you use ngModel
|
|
34
|
+
DigitsOnlyDirective,
|
|
35
|
+
],
|
|
36
|
+
template: `<input digitsOnly formControlName="quantity" />`,
|
|
49
37
|
})
|
|
50
|
-
export class ExampleComponent {
|
|
51
|
-
amountControl = new FormControl('');
|
|
52
|
-
}
|
|
38
|
+
export class ExampleComponent {}
|
|
53
39
|
```
|
|
54
40
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
Standalone directives can still be used inside NgModule-based components — just add it to that component's own `imports` array if the component itself is standalone, or import it directly where the input lives:
|
|
41
|
+
In an NgModule-based app, standalone directives can be added directly to that module's `imports` array too:
|
|
58
42
|
|
|
59
43
|
```typescript
|
|
60
|
-
@
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
44
|
+
@NgModule({
|
|
45
|
+
imports: [
|
|
46
|
+
FormsModule,
|
|
47
|
+
ReactiveFormsModule,
|
|
48
|
+
DigitsOnlyDirective,
|
|
49
|
+
],
|
|
50
|
+
declarations: [MyComponent],
|
|
64
51
|
})
|
|
52
|
+
export class MyFeatureModule {}
|
|
65
53
|
```
|
|
66
54
|
|
|
67
|
-
|
|
55
|
+
## Your first input
|
|
68
56
|
|
|
69
|
-
|
|
57
|
+
```html
|
|
58
|
+
<input digitsOnly />
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
That's it. The field now only accepts digits `0–9`. Nothing else gets through.
|
|
62
|
+
|
|
63
|
+
```html
|
|
64
|
+
<input digitsOnly formControlName="quantity" />
|
|
65
|
+
<input digitsOnly [(ngModel)]="quantity" name="quantity" />
|
|
66
|
+
```
|
|
70
67
|
|
|
71
|
-
|
|
68
|
+
## All inputs at a glance
|
|
69
|
+
|
|
70
|
+
| Input | Type | Default | What it does |
|
|
72
71
|
|---|---|---|---|
|
|
73
|
-
| `
|
|
74
|
-
| `
|
|
75
|
-
| `
|
|
76
|
-
| `
|
|
77
|
-
| `
|
|
78
|
-
| `
|
|
79
|
-
| `
|
|
80
|
-
| `
|
|
81
|
-
| `
|
|
72
|
+
| `decimalPlaces` | `number \| null` | `0` | Decimal places: `0` = integers, `N` = exactly N, `null` = unlimited |
|
|
73
|
+
| `thousandSeparator` | `'' \| ',' \| '.' \| ' ' \| '_'` | `''` | Visual grouping character |
|
|
74
|
+
| `prefix` | `string` | `''` | Text shown before the number (e.g. `$`) |
|
|
75
|
+
| `suffix` | `string` | `''` | Text shown after the number (e.g. `%`) |
|
|
76
|
+
| `allowNegative` | `boolean` | `false` | Allow a leading minus sign |
|
|
77
|
+
| `leadingZeros` | `boolean` | `false` | Preserve leading zeros like `007` |
|
|
78
|
+
| `maxLength` | `number \| null` | `null` | Max raw digit count |
|
|
79
|
+
| `min` | `number \| null` | `null` | Minimum value (validation) |
|
|
80
|
+
| `max` | `number \| null` | `null` | Maximum value (validation) |
|
|
81
|
+
| `outputType` | `'number' \| 'string'` | `'number'` | Type emitted to the model |
|
|
82
|
+
| `pattern` | `NamedPattern \| string` | `''` | Display format mask |
|
|
83
|
+
| `convertEasternNumerals` | `boolean` | `true` | Convert Arabic/Persian digits |
|
|
84
|
+
|
|
85
|
+
## decimalPlaces
|
|
86
|
+
|
|
87
|
+
Controls how many digits are allowed after the decimal point.
|
|
88
|
+
|
|
89
|
+
```html
|
|
90
|
+
<!-- 0 (default) — integers only, decimal point blocked -->
|
|
91
|
+
<input digitsOnly formControlName="quantity" />
|
|
92
|
+
<!-- user types: 1234 model: 1234 -->
|
|
93
|
+
|
|
94
|
+
<!-- N — exactly N decimal places -->
|
|
95
|
+
<input digitsOnly [decimalPlaces]="2" formControlName="price" />
|
|
96
|
+
<!-- user types: 99.99 model: 99.99 -->
|
|
97
|
+
|
|
98
|
+
<!-- null — unlimited decimal places, only single-dot rule enforced -->
|
|
99
|
+
<input digitsOnly [decimalPlaces]="null" formControlName="exchangeRate" />
|
|
100
|
+
<!-- user types: 1.23456789 model: 1.23456789 -->
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
A keystroke that would exceed the allowed decimal places is blocked outright.
|
|
104
|
+
When `null`, any number of decimal digits is accepted but only one decimal point is allowed.
|
|
105
|
+
|
|
106
|
+
> `null` follows the same "no limit" convention used by `maxLength`, `min`, and `max`.
|
|
107
|
+
|
|
108
|
+
## thousandSeparator
|
|
109
|
+
|
|
110
|
+
Display-only formatting — the model always gets the plain number.
|
|
111
|
+
|
|
112
|
+
```html
|
|
113
|
+
<input digitsOnly thousandSeparator="," formControlName="salary" />
|
|
114
|
+
<!-- display: 1,234,567 model: 1234567 -->
|
|
115
|
+
|
|
116
|
+
<input digitsOnly thousandSeparator="." [decimalPlaces]="2" formControlName="amount" />
|
|
117
|
+
<!-- display: 1.234.567,89 model: 1234567.89 -->
|
|
118
|
+
<!-- setting "." as the thousands separator auto-switches the decimal char to "," -->
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Also accepts `' '` (space) and `'_'` (underscore).
|
|
122
|
+
|
|
123
|
+
## prefix and suffix
|
|
124
|
+
|
|
125
|
+
```html
|
|
126
|
+
<input digitsOnly prefix="$" formControlName="price" />
|
|
127
|
+
<!-- display: $1234 model: 1234 -->
|
|
128
|
+
|
|
129
|
+
<input digitsOnly prefix="€" suffix=" EUR" [decimalPlaces]="2" formControlName="amount" />
|
|
130
|
+
<!-- display: €1,234.56 EUR model: 1234.56 -->
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Both are stripped before the value reaches your model.
|
|
134
|
+
|
|
135
|
+
> **Angular Material note:** The label correctly floats only when there is actual numeric
|
|
136
|
+
> content. An empty field always writes `""` to the native input so `MatInput`'s empty
|
|
137
|
+
> check passes correctly — even when `prefix` or `suffix` is set.
|
|
138
|
+
|
|
139
|
+
## allowNegative
|
|
140
|
+
|
|
141
|
+
```html
|
|
142
|
+
<input digitsOnly [allowNegative]="true" formControlName="temperature" />
|
|
143
|
+
<!-- user can type: -42 model: -42 -->
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
The minus sign is only valid as the first character, and works correctly even with `prefix` set.
|
|
147
|
+
|
|
148
|
+
## leadingZeros
|
|
149
|
+
|
|
150
|
+
By default, leading zeros are stripped in number mode.
|
|
151
|
+
|
|
152
|
+
```html
|
|
153
|
+
<input digitsOnly outputType="string" [leadingZeros]="true" [maxLength]="5" formControlName="zip" />
|
|
154
|
+
<!-- user types: 01234 model: '01234' (not 1234) -->
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
When `pattern` is set, leading zeros are always preserved automatically.
|
|
158
|
+
|
|
159
|
+
## maxLength
|
|
160
|
+
|
|
161
|
+
```html
|
|
162
|
+
<input digitsOnly [maxLength]="5" formControlName="pin" />
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
When `pattern` is set, `maxLength` is derived automatically from the number of `0` slots — any manual value is ignored.
|
|
166
|
+
|
|
167
|
+
## min and max
|
|
168
|
+
|
|
169
|
+
Only apply in `outputType="number"` mode.
|
|
170
|
+
|
|
171
|
+
```html
|
|
172
|
+
<input digitsOnly [min]="0" [max]="999" formControlName="score" #scoreCtrl="ngModel" />
|
|
173
|
+
|
|
174
|
+
<p *ngIf="scoreCtrl.errors?.['min']">Minimum value is {{ scoreCtrl.errors?.['min'].min }}</p>
|
|
175
|
+
<p *ngIf="scoreCtrl.errors?.['max']">Maximum value is {{ scoreCtrl.errors?.['max'].max }}</p>
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
Error payloads: `{ min: 0, actual: -5 }` / `{ max: 999, actual: 1200 }`.
|
|
179
|
+
|
|
180
|
+
## outputType — the most important decision
|
|
181
|
+
|
|
182
|
+
**`outputType="number"` (default)** — model gets a JS `number` or `null`. Use for prices, quantities, anything you'll do arithmetic with.
|
|
183
|
+
|
|
184
|
+
**`outputType="string"`** — model gets a JS `string` or `null`. Use for card numbers, phone numbers, postal codes, SSNs — identifiers, not quantities.
|
|
185
|
+
|
|
186
|
+
Why it matters:
|
|
187
|
+
|
|
188
|
+
- Leading zeros are lost in number mode: `01234` → `1234`
|
|
189
|
+
- 16-digit card numbers exceed `Number.MAX_SAFE_INTEGER` (`9007199254740991`) and get silently corrupted if stored as a number
|
|
190
|
+
|
|
191
|
+
```typescript
|
|
192
|
+
// WRONG
|
|
193
|
+
cardNumber: number = 4111111111111111; // stored as 4111111111111112 — last digit wrong
|
|
194
|
+
|
|
195
|
+
// CORRECT
|
|
196
|
+
cardNumber: string = '4111111111111111'; // exact
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
## pattern — auto formatting
|
|
200
|
+
|
|
201
|
+
```html
|
|
202
|
+
<input digitsOnly pattern="0000 0000 0000 0000" formControlName="card" />
|
|
203
|
+
<!-- display: 4111 1111 1111 1111 model: '4111111111111111' -->
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
Setting `pattern` automatically:
|
|
207
|
+
|
|
208
|
+
| Effect | Why |
|
|
209
|
+
|---|---|
|
|
210
|
+
| Forces `outputType="string"` | Patterns are for identifiers, never arithmetic |
|
|
211
|
+
| Derives `maxLength` from slot count | No need to set it separately |
|
|
212
|
+
| Forces `leadingZeros="true"` | Every digit position is significant |
|
|
213
|
+
| Disables `thousandSeparator` | Patterns have their own separators |
|
|
214
|
+
| Disables `decimalPlaces` | Patterns are for integers/identifiers |
|
|
215
|
+
| Disables `allowNegative` | Identifiers are never negative |
|
|
216
|
+
|
|
217
|
+
### Named patterns
|
|
218
|
+
|
|
219
|
+
| Name | Slots | Example |
|
|
220
|
+
|---|---|---|
|
|
221
|
+
| `card` | 16 | `4111 1111 1111 1111` |
|
|
222
|
+
| `card-amex` | 15 | `3782 822463 10005` |
|
|
223
|
+
| `expiry` | 4 | `12/26` |
|
|
224
|
+
| `cvv` | 3 | `123` |
|
|
225
|
+
| `cvv-amex` | 4 | `1234` |
|
|
226
|
+
| `phone-us` | 10 | `(555) 867-5309` |
|
|
227
|
+
| `ssn` | 9 | `123-45-6789` |
|
|
228
|
+
| `date` | 8 | `01/01/1990` |
|
|
229
|
+
| `time` | 4 | `09:30` |
|
|
230
|
+
| `sort-code` | 6 | `20-00-00` |
|
|
231
|
+
| `bsb` | 6 | `062-000` |
|
|
232
|
+
|
|
233
|
+
```html
|
|
234
|
+
<input digitsOnly pattern="card" formControlName="cardNumber" />
|
|
235
|
+
<input digitsOnly pattern="expiry" formControlName="expiry" />
|
|
236
|
+
<input digitsOnly pattern="ssn" formControlName="ssn" />
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
### Custom patterns
|
|
240
|
+
|
|
241
|
+
Any string not in the named list is used as a raw pattern — `0` for a digit slot, anything else as a literal separator.
|
|
242
|
+
|
|
243
|
+
```html
|
|
244
|
+
<input digitsOnly pattern="000 000" formControlName="otp" />
|
|
245
|
+
<!-- display: 123 456 model: '123456' -->
|
|
246
|
+
|
|
247
|
+
<input digitsOnly pattern="0000-0000-0000" formControlName="account" />
|
|
248
|
+
<!-- display: 1234-5678-9012 model: '123456789012' -->
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
Separators are only inserted once more digits are coming, so you never get a trailing separator mid-type.
|
|
252
|
+
|
|
253
|
+
## convertEasternNumerals
|
|
254
|
+
|
|
255
|
+
Arabic and Persian keyboards produce different Unicode digit characters:
|
|
256
|
+
|
|
257
|
+
| Script | Characters |
|
|
258
|
+
|---|---|
|
|
259
|
+
| Western | `0 1 2 3 4 5 6 7 8 9` |
|
|
260
|
+
| Arabic-Indic | `٠ ١ ٢ ٣ ٤ ٥ ٦ ٧ ٨ ٩` |
|
|
261
|
+
| Persian/Farsi | `۰ ۱ ۲ ۳ ۴ ۵ ۶ ۷ ۸ ۹` |
|
|
262
|
+
|
|
263
|
+
By default (`convertEasternNumerals="true"`), both typing and pasting Eastern digits work transparently, with the Arabic decimal (`٫`) and thousands (`٬`) separators normalized automatically.
|
|
264
|
+
|
|
265
|
+
```html
|
|
266
|
+
<input digitsOnly [convertEasternNumerals]="false" formControlName="code" />
|
|
267
|
+
<!-- Eastern digits now blocked — only ASCII 0-9 accepted -->
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
Conversion is unicode-range-safe — it can never accidentally transform a comma, dollar sign, or letter.
|
|
271
|
+
|
|
272
|
+
## Validation errors
|
|
273
|
+
|
|
274
|
+
Implements Angular's `Validator` interface — errors land on `control.errors` automatically.
|
|
275
|
+
|
|
276
|
+
| Error key | When it fires | Payload |
|
|
277
|
+
|---|---|---|
|
|
278
|
+
| `min` | Value below `[min]` | `{ min, actual }` |
|
|
279
|
+
| `max` | Value above `[max]` | `{ max, actual }` |
|
|
280
|
+
| `maxLength` | Raw digit count exceeds `[maxLength]` | `{ maxLength, actual }` |
|
|
281
|
+
| `patternIncomplete` | Pattern mode, not all slots filled | `{ required, actual, pattern }` |
|
|
282
|
+
|
|
283
|
+
```html
|
|
284
|
+
<input digitsOnly pattern="card" formControlName="cardNumber" />
|
|
285
|
+
<p *ngIf="form.get('cardNumber')?.errors?.['patternIncomplete']">
|
|
286
|
+
Enter all {{ form.get('cardNumber')?.errors?.['patternIncomplete']?.required }} digits
|
|
287
|
+
</p>
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
Directive errors merge with Angular's own validators (e.g. `Validators.required`) on the same `control.errors` object.
|
|
291
|
+
|
|
292
|
+
## Reactive Forms example
|
|
293
|
+
|
|
294
|
+
```typescript
|
|
295
|
+
this.form = this.fb.group({
|
|
296
|
+
cardNumber: [null, Validators.required],
|
|
297
|
+
expiry: [null, Validators.required],
|
|
298
|
+
cvv: [null, Validators.required],
|
|
299
|
+
amount: [null, Validators.required],
|
|
300
|
+
});
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
```html
|
|
304
|
+
<form [formGroup]="form" (ngSubmit)="pay()">
|
|
305
|
+
<input digitsOnly pattern="card" formControlName="cardNumber" placeholder="4111 1111 1111 1111" />
|
|
306
|
+
<input digitsOnly pattern="expiry" formControlName="expiry" placeholder="MM/YY" />
|
|
307
|
+
<input digitsOnly pattern="cvv" formControlName="cvv" placeholder="123" />
|
|
308
|
+
<input digitsOnly [decimalPlaces]="2" thousandSeparator="," prefix="$" [min]="0.01" formControlName="amount" />
|
|
309
|
+
<button type="submit" [disabled]="form.invalid">Pay</button>
|
|
310
|
+
</form>
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
```typescript
|
|
314
|
+
onSubmit() {
|
|
315
|
+
console.log(this.form.value);
|
|
316
|
+
// {
|
|
317
|
+
// cardNumber: '4111111111111111', // string, no spaces
|
|
318
|
+
// expiry: '1226', // string, no slash
|
|
319
|
+
// cvv: '123',
|
|
320
|
+
// amount: 49.99 // number
|
|
321
|
+
// }
|
|
322
|
+
}
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
## Type safety — NamedPattern
|
|
326
|
+
|
|
327
|
+
```typescript
|
|
328
|
+
import { NamedPattern } from 'ngx-digits-only';
|
|
329
|
+
|
|
330
|
+
export class MyComponent {
|
|
331
|
+
selectedPattern: NamedPattern = 'card'; // autocomplete + compile-time typo checking
|
|
332
|
+
customPattern = '000-0000'; // custom strings still accepted
|
|
333
|
+
}
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
```html
|
|
337
|
+
<input digitsOnly [pattern]="selectedPattern" formControlName="id" />
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
`NamedPattern` uses the `(string & {})` trick internally so IDE autocomplete for named patterns survives alongside free-form custom pattern strings.
|
|
341
|
+
|
|
342
|
+
## Standalone Eastern numeral utilities
|
|
343
|
+
|
|
344
|
+
Zero-dependency functions, usable outside Angular entirely (React, Vue, Node, plain TS):
|
|
345
|
+
|
|
346
|
+
```typescript
|
|
347
|
+
import { convertEasternDigits, hasEasternDigits, getDigitScript, toWesternNumber } from 'ngx-digits-only';
|
|
348
|
+
|
|
349
|
+
convertEasternDigits('١٢٣'); // '123'
|
|
350
|
+
hasEasternDigits('١٢٣'); // true
|
|
351
|
+
getDigitScript('۴۵۶'); // 'persian'
|
|
352
|
+
toWesternNumber('١٢٣٫٤٥'); // 123.45
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
## Common mistakes
|
|
356
|
+
|
|
357
|
+
**Using `number` for a card number** — exceeds `Number.MAX_SAFE_INTEGER` and corrupts digits. Use `outputType="string"` or, better, `pattern="card"` which handles it automatically.
|
|
358
|
+
|
|
359
|
+
**Setting `[maxLength]` alongside `pattern`** — ignored; pattern derives it from slot count.
|
|
360
|
+
|
|
361
|
+
**Expecting `min`/`max` with `outputType="string"`** — silently ignored in string mode; only works with `outputType="number"`.
|
|
362
|
+
|
|
363
|
+
**Expecting `decimalPlaces` to work with `pattern`** — ignored when a pattern is set; patterns are always integer-only identifiers.
|
|
364
|
+
|
|
365
|
+
**Forgetting `FormsModule`/`ReactiveFormsModule`** — required alongside `DigitsOnlyDirective` for `ngModel`/`formControlName` to work.
|
|
366
|
+
|
|
367
|
+
## FAQ
|
|
368
|
+
|
|
369
|
+
**Can I combine `prefix`/`suffix` with `pattern`?** Yes — they wrap the formatted pattern display; the model still gets the raw digits.
|
|
370
|
+
|
|
371
|
+
**Can I pre-fill from the server?** Yes, via `fb.group()` initial values or `patchValue()` — `writeValue()` formats the display automatically.
|
|
372
|
+
|
|
373
|
+
**Why `null` instead of `0` for an empty field?** By design, to distinguish "user typed zero" from "user left it blank."
|
|
374
|
+
|
|
375
|
+
**Why is `decimalPlaces` typed as `number | null` now?** `null` means unlimited decimal places — same convention as `maxLength`, `min`, and `max`. `0` still means integers only and is still the default, so existing code is unaffected.
|
|
376
|
+
|
|
377
|
+
**Does it work with Angular Material?** Yes — including correct label floating behaviour. The directive writes `""` to the native input when the field is empty, even when `prefix` or `suffix` is set, so `MatInput` detects the empty state correctly.
|
|
378
|
+
|
|
379
|
+
**Does it work with Angular signal-based forms?** Yes — it implements `ControlValueAccessor`, compatible with any Angular form API.
|
|
380
|
+
|
|
381
|
+
**Can I use it without a form?** Yes:
|
|
382
|
+
```html
|
|
383
|
+
<input digitsOnly (input)="onInput($event.target.value)" />
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
## Changelog
|
|
387
|
+
|
|
388
|
+
### 1.1.0
|
|
389
|
+
|
|
390
|
+
**Added**
|
|
391
|
+
- `decimalPlaces` now accepts `null` for unlimited decimal places (single-dot rule still enforced). Existing `0` / `N` behavior is unchanged — no breaking change.
|
|
392
|
+
|
|
393
|
+
**Fixed**
|
|
394
|
+
- Angular Material (`MatInput`) label was permanently floated when `prefix` or `suffix` was set on an empty field. The directive now writes `""` to the native input when empty so Material's empty check passes correctly.
|
|
395
|
+
|
|
396
|
+
### 1.0.5
|
|
397
|
+
|
|
398
|
+
**Added**
|
|
399
|
+
- RTL / LTR direction support — automatic via `getComputedStyle`, no extra input required
|
|
400
|
+
- `convertEasternNumerals` input — Arabic-Indic and Persian digit conversion on keystroke and paste
|
|
401
|
+
- `pattern` input with 11 named aliases and custom raw pattern support
|
|
402
|
+
- `outputType` input — `'number'` or `'string'`
|
|
403
|
+
- `NamedPattern` exported type — IDE autocomplete and compile-time safety
|
|
404
|
+
- `allowNegative` now works correctly when `prefix` is set
|
|
405
|
+
|
|
406
|
+
**Fixed**
|
|
407
|
+
- Eastern digits (Arabic/Persian) were blocked on `keydown` because `SINGLE_DIGIT` only matches ASCII — fixed with Unicode range check
|
|
408
|
+
|
|
409
|
+
### 1.0.0
|
|
410
|
+
|
|
411
|
+
Initial release.
|
|
82
412
|
|
|
83
413
|
## Compatibility
|
|
84
414
|
|
|
85
|
-
Requires Angular `>=16.0.0
|
|
415
|
+
Requires Angular `>=16.0.0`.
|
|
86
416
|
|
|
87
417
|
## License
|
|
88
418
|
|