@@ -32,26 +32,29 @@ enum InputState {
32
32
} )
33
33
export class CodeInputComponent implements AfterViewInit , OnInit , OnChanges , AfterViewChecked , CodeInputComponentConfig {
34
34
35
- @ViewChildren ( 'input' ) inputsList : QueryList < ElementRef > ;
35
+ @ViewChildren ( 'input' ) inputsList ! : QueryList < ElementRef > ;
36
36
37
- @Input ( ) readonly codeLength ;
38
- @Input ( ) readonly inputType ;
39
- @Input ( ) readonly initialFocusField ?: number ;
37
+ @Input ( ) codeLength ! : number ;
38
+ @Input ( ) inputType ! : string ;
39
+ @Input ( ) initialFocusField ?: number ;
40
40
/** @deprecated Use isCharsCode prop instead. */
41
41
@Input ( ) isNonDigitsCode = false ;
42
- @Input ( ) isCharsCode ;
43
- @Input ( ) isCodeHidden ;
44
- @Input ( ) isPrevFocusableAfterClearing ;
45
- @Input ( ) isFocusingOnLastByClickIfFilled ;
46
- @Input ( ) code ?: string | number ;
42
+ @Input ( ) isCharsCode ! : boolean ;
43
+ @Input ( ) isCodeHidden ! : boolean ;
44
+ @Input ( ) isPrevFocusableAfterClearing ! : boolean ;
45
+ @Input ( ) isFocusingOnLastByClickIfFilled ! : boolean ;
46
+ @Input ( ) code ?: string | number ;
47
47
48
48
@Output ( ) readonly codeChanged = new EventEmitter < string > ( ) ;
49
49
@Output ( ) readonly codeCompleted = new EventEmitter < string > ( ) ;
50
50
51
- public placeholders : number [ ] ;
51
+ public placeholders ! : number [ ] ;
52
52
53
53
private inputs : HTMLInputElement [ ] = [ ] ;
54
54
private inputsStates : InputState [ ] = [ ] ;
55
+
56
+ // tslint:disable-next-line:variable-name
57
+ private _codeLength ! : number ;
55
58
private state = {
56
59
isFocusingAfterAppearingCompleted : false ,
57
60
isInitialFocusFieldEnabled : false
@@ -74,6 +77,7 @@ export class CodeInputComponent implements AfterViewInit, OnInit, OnChanges, Aft
74
77
continue ;
75
78
}
76
79
80
+ // @ts -ignore
77
81
this [ prop ] = config [ prop ] ;
78
82
}
79
83
}
@@ -83,7 +87,9 @@ export class CodeInputComponent implements AfterViewInit, OnInit, OnChanges, Aft
83
87
*/
84
88
85
89
ngOnInit ( ) : void {
86
- this . placeholders = Array ( this . codeLength ) . fill ( 1 ) ;
90
+ // defining internal code length prop for skipping external prop updates
91
+ this . _codeLength = this . codeLength ;
92
+ this . placeholders = Array ( this . _codeLength ) . fill ( 1 ) ;
87
93
this . state . isInitialFocusFieldEnabled = ! this . isEmpty ( this . initialFocusField ) ;
88
94
}
89
95
@@ -118,14 +124,14 @@ export class CodeInputComponent implements AfterViewInit, OnInit, OnChanges, Aft
118
124
}
119
125
120
126
const target = e . target ;
121
- const last = this . inputs [ this . codeLength - 1 ] ;
127
+ const last = this . inputs [ this . _codeLength - 1 ] ;
122
128
// already focused
123
129
if ( target === last ) {
124
130
return ;
125
131
}
126
132
127
133
// check filling
128
- const isFilled = this . getCurrentFilledCode ( ) . length >= this . codeLength ;
134
+ const isFilled = this . getCurrentFilledCode ( ) . length >= this . _codeLength ;
129
135
if ( ! isFilled ) {
130
136
return ;
131
137
}
@@ -155,7 +161,7 @@ export class CodeInputComponent implements AfterViewInit, OnInit, OnChanges, Aft
155
161
this . setInputValue ( target , value . toString ( ) . charAt ( 0 ) ) ;
156
162
this . emitChanges ( ) ;
157
163
158
- if ( next > this . codeLength - 1 ) {
164
+ if ( next > this . _codeLength - 1 ) {
159
165
target . blur ( ) ;
160
166
return ;
161
167
}
@@ -174,7 +180,8 @@ export class CodeInputComponent implements AfterViewInit, OnInit, OnChanges, Aft
174
180
}
175
181
176
182
// Convert paste text into iterable
177
- const values = data . split ( '' ) ;
183
+ // tslint:disable-next-line:no-non-null-assertion
184
+ const values = data ! . split ( '' ) ;
178
185
let valIndex = 0 ;
179
186
180
187
for ( let j = i ; j < this . inputs . length ; j ++ ) {
@@ -228,15 +235,6 @@ export class CodeInputComponent implements AfterViewInit, OnInit, OnChanges, Aft
228
235
}
229
236
}
230
237
231
- isInputElementEmptyAt ( index : number ) : boolean {
232
- const input = this . inputs [ index ] ;
233
- if ( ! input ) {
234
- return true ;
235
- }
236
-
237
- return this . isEmpty ( input . value ) ;
238
- }
239
-
240
238
private onInputCodeChanges ( ) : void {
241
239
if ( ! this . inputs . length ) {
242
240
return ;
@@ -249,16 +247,20 @@ export class CodeInputComponent implements AfterViewInit, OnInit, OnChanges, Aft
249
247
return ;
250
248
}
251
249
252
- const chars = this . code . toString ( ) . trim ( ) . split ( '' ) ;
250
+ // tslint:disable-next-line:no-non-null-assertion
251
+ const chars = this . code ! . toString ( ) . trim ( ) . split ( '' ) ;
253
252
// checking if all the values are correct
253
+ let isAllCharsAreAllowed = true ;
254
254
for ( const char of chars ) {
255
255
if ( ! this . canInputValue ( char ) ) {
256
- return ;
256
+ isAllCharsAreAllowed = false ;
257
+ break ;
257
258
}
258
259
}
259
260
260
261
this . inputs . forEach ( ( input : HTMLInputElement , index : number ) => {
261
- this . setInputValue ( input , chars [ index ] ) ;
262
+ const value = isAllCharsAreAllowed ? chars [ index ] : null ;
263
+ this . setInputValue ( input , value ) ;
262
264
} ) ;
263
265
}
264
266
@@ -271,6 +273,10 @@ export class CodeInputComponent implements AfterViewInit, OnInit, OnChanges, Aft
271
273
return ;
272
274
}
273
275
276
+ if ( ! this . initialFocusField ) {
277
+ return ;
278
+ }
279
+
274
280
this . inputs [ this . initialFocusField ] . focus ( ) ;
275
281
this . state . isFocusingAfterAppearingCompleted = document . activeElement === this . inputs [ this . initialFocusField ] ;
276
282
}
@@ -284,7 +290,7 @@ export class CodeInputComponent implements AfterViewInit, OnInit, OnChanges, Aft
284
290
285
291
this . codeChanged . emit ( code ) ;
286
292
287
- if ( code . length >= this . codeLength ) {
293
+ if ( code . length >= this . _codeLength ) {
288
294
this . codeCompleted . emit ( code ) ;
289
295
}
290
296
}
@@ -327,8 +333,20 @@ export class CodeInputComponent implements AfterViewInit, OnInit, OnChanges, Aft
327
333
328
334
private setInputValue ( input : HTMLInputElement , value : any ) : void {
329
335
const isEmpty = this . isEmpty ( value ) ;
330
- input . value = isEmpty ? null : value ;
331
- input . className = isEmpty ? '' : 'has-value' ;
336
+ const valueClassCSS = 'has-value' ;
337
+ const emptyClassCSS = 'empty' ;
338
+ if ( isEmpty ) {
339
+ input . value = '' ;
340
+ input . classList . remove ( valueClassCSS ) ;
341
+ // tslint:disable-next-line:no-non-null-assertion
342
+ input . parentElement ! . classList . add ( emptyClassCSS ) ;
343
+ }
344
+ else {
345
+ input . value = value ;
346
+ input . classList . add ( valueClassCSS ) ;
347
+ // tslint:disable-next-line:no-non-null-assertion
348
+ input . parentElement ! . classList . remove ( emptyClassCSS ) ;
349
+ }
332
350
}
333
351
334
352
private canInputValue ( value : any ) : boolean {
0 commit comments