diff --git a/projects/ng-otp-input/package.json b/projects/ng-otp-input/package.json
index 3e66c18..7488e95 100644
--- a/projects/ng-otp-input/package.json
+++ b/projects/ng-otp-input/package.json
@@ -1,6 +1,6 @@
{
"name": "ng-otp-input",
- "version": "2.0.7",
+ "version": "2.0.8",
"description": "A fully customizable, one-time password input component for the web built with Angular.",
"author": {"name": "jitender"},
"homepage": "https://github.com/code-farmz/ng-otp-input#readme",
diff --git a/projects/ng-otp-input/src/lib/components/ng-otp-input/ng-otp-input.component.html b/projects/ng-otp-input/src/lib/components/ng-otp-input/ng-otp-input.component.html
index 3b935e4..7cf4cda 100644
--- a/projects/ng-otp-input/src/lib/components/ng-otp-input/ng-otp-input.component.html
+++ b/projects/ng-otp-input/src/lib/components/ng-otp-input/ng-otp-input.component.html
@@ -8,7 +8,7 @@
[ngStyle]="config.inputStyles"
class="otp-input {{config.inputClass}}" autocomplete="one-time-code"
[formControl]="otpForm.controls[item]" #inp [id]="getBoxId(i)"
- (keyup)="onKeyUp($event,i)" (input)="onInput($event,i)" (keydown)="onKeyDown($event,i)" [ngClass]="{'error-input': (config?.showError && formCtrl?.invalid && (formCtrl?.dirty || formCtrl?.touched))}">
+ (keyup)="onKeyUp($event,i)" (input)="onInput($event,i)" (keydown)="onKeyDown($event,i)" [ngClass]="{'error-input': (config?.showError && formControl?.invalid && (formControl?.dirty || formControl?.touched))}">
{{config.separator}}
diff --git a/projects/ng-otp-input/src/lib/components/ng-otp-input/ng-otp-input.component.ts b/projects/ng-otp-input/src/lib/components/ng-otp-input/ng-otp-input.component.ts
index c833807..8338478 100644
--- a/projects/ng-otp-input/src/lib/components/ng-otp-input/ng-otp-input.component.ts
+++ b/projects/ng-otp-input/src/lib/components/ng-otp-input/ng-otp-input.component.ts
@@ -5,8 +5,10 @@ import {
Output,
AfterViewInit,
Inject,
- forwardRef} from '@angular/core';
-import { FormGroup, FormControl, ReactiveFormsModule, NG_VALUE_ACCESSOR, ControlValueAccessor } from '@angular/forms';
+ forwardRef,
+ Injector
+} from '@angular/core';
+import { FormGroup, FormControl, ReactiveFormsModule, NG_VALUE_ACCESSOR, ControlValueAccessor, NgControl } from '@angular/forms';
import { Config } from '../../models/config';
import { KeyboardUtil } from '../../utils/keyboard-util';
import { DOCUMENT, NgClass, NgFor, NgIf, NgStyle } from '@angular/common';
@@ -15,64 +17,69 @@ import { takeUntil } from 'rxjs/operators';
import { ObjectUtil } from '../../utils/object-util';
import { OnDestroy } from '@angular/core';
@Component({
- // tslint:disable-next-line: component-selector
- selector: 'ng-otp-input, ngx-otp-input',
- templateUrl: './ng-otp-input.component.html',
- styleUrls: ['./ng-otp-input.component.scss'],
- imports: [ReactiveFormsModule, NgIf, NgFor, NgStyle, NgClass],
- providers: [
- {
- provide: NG_VALUE_ACCESSOR,
- useExisting: forwardRef(() => NgOtpInputComponent),
- multi: true,
- },
- ]
+ // tslint:disable-next-line: component-selector
+ selector: 'ng-otp-input, ngx-otp-input',
+ templateUrl: './ng-otp-input.component.html',
+ styleUrls: ['./ng-otp-input.component.scss'],
+ imports: [ReactiveFormsModule, NgIf, NgFor, NgStyle, NgClass],
+ providers: [
+ {
+ provide: NG_VALUE_ACCESSOR,
+ useExisting: forwardRef(() => NgOtpInputComponent),
+ multi: true,
+ },
+ ]
})
-export class NgOtpInputComponent implements OnInit, AfterViewInit,OnDestroy,ControlValueAccessor {
+export class NgOtpInputComponent implements OnInit, AfterViewInit, OnDestroy, ControlValueAccessor {
@Input() config: Config = { length: 4 };
/**
* @deprecated formCtrl is deprecated and will be removed soon. Use `FormControl` instead.
*/
- @Input() formCtrl:FormControl;
- @Input() set disabled(isDisabled:boolean){
+ @Input() formCtrl: FormControl;
+ @Input() set disabled(isDisabled: boolean) {
this.setDisabledState(isDisabled);
}
@Output() onBlur = new Subject();
@Output() onInputChange = new Subject();
otpForm: FormGroup;
- currentVal:string;
+ currentVal: string;
inputControls: FormControl[] = new Array(this.config.length);
- componentKey = Math.random()
- .toString(36)
- .substring(2) + new Date().getTime().toString(36);
- get inputType(){
- return this.config?.isPasswordInput
- ? 'password'
- : this.config?.allowNumbersOnly
- ? 'tel'
- : 'text';
+ componentKey = Math.random()
+ .toString(36)
+ .substring(2) + new Date().getTime().toString(36);
+ get inputType() {
+ return this.config?.isPasswordInput
+ ? 'password'
+ : this.config?.allowNumbersOnly
+ ? 'tel'
+ : 'text';
}
- get controlKeys(){ return ObjectUtil.keys(this.otpForm?.controls)};
+ get controlKeys() { return ObjectUtil.keys(this.otpForm?.controls) };
private destroy$ = new Subject();
private activeFocusCount = 0;
- private onChange: (value: any) => void = () => {};
- private onTouched: () => void = () => {};
- private _isDisabled: boolean = false;
+ private onChange: (value: any) => void = () => { };
+ private onTouched: () => void = () => { };
+ private _isDisabled: boolean = false;
+ get formControl() {
+ return this.formCtrl ?? this.inj?.get(NgControl);
+ }
+ constructor(@Inject(DOCUMENT) private document: Document, private inj: Injector) {
+
+ }
- constructor(@Inject(DOCUMENT) private document: Document) {}
ngOnInit() {
this.otpForm = new FormGroup({});
for (let index = 0; index < this.config.length; index++) {
this.otpForm.addControl(this.getControlName(index), new FormControl());
}
- this.otpForm.valueChanges.pipe(takeUntil(this.destroy$)).subscribe((v:object)=>{
+ this.otpForm.valueChanges.pipe(takeUntil(this.destroy$)).subscribe((v: object) => {
ObjectUtil.keys(this.otpForm.controls).forEach((k) => {
var val = this.otpForm.controls[k].value;
- if(val && val.length>1){
+ if (val && val.length > 1) {
if (val.length >= this.config.length) {
this.setValue(val);
- }else{
+ } else {
this.rebuildValue();
}
}
@@ -103,7 +110,7 @@ export class NgOtpInputComponent implements OnInit, AfterViewInit,OnDestroy,Cont
}
onFocusIn() {
- this.onTouched();
+ this.onTouched();
this.activeFocusCount++;
}
@@ -111,7 +118,7 @@ export class NgOtpInputComponent implements OnInit, AfterViewInit,OnDestroy,Cont
setTimeout(() => {
this.activeFocusCount--;
if (this.activeFocusCount === 0) {
- this.onTouched();
+ this.onTouched();
this.onBlur.next();
}
}, 0);
@@ -132,64 +139,64 @@ export class NgOtpInputComponent implements OnInit, AfterViewInit,OnDestroy,Cont
return `ctrl_${idx}`;
}
- onKeyDown($event, inputIdx){
+ onKeyDown($event, inputIdx) {
const prevInputId = this.getBoxId(inputIdx - 1);
const currentInputId = this.getBoxId(inputIdx);
const nextInputId = this.getBoxId(inputIdx + 1);
if (KeyboardUtil.ifSpacebar($event)) {
$event.preventDefault();
return false;
- }
- if (KeyboardUtil.ifBackspace($event)) {
- if(!$event.target.value){
- this.clearInput(prevInputId,inputIdx-1);
+ }
+ if (KeyboardUtil.ifBackspace($event)) {
+ if (!$event.target.value) {
+ this.clearInput(prevInputId, inputIdx - 1);
this.setSelected(prevInputId);
- }else{
- this.clearInput(currentInputId,inputIdx);
+ } else {
+ this.clearInput(currentInputId, inputIdx);
}
this.rebuildValue();
return;
}
if (KeyboardUtil.ifDelete($event)) {
- if(!$event.target.value){
- this.clearInput(prevInputId,inputIdx-1);
+ if (!$event.target.value) {
+ this.clearInput(prevInputId, inputIdx - 1);
this.setSelected(prevInputId);
- }else{
- this.clearInput(currentInputId,inputIdx);
+ } else {
+ this.clearInput(currentInputId, inputIdx);
}
this.rebuildValue();
return;
}
-
+
}
- hasVal(val){
+ hasVal(val) {
return val != null && val != undefined && (!val?.trim || val.trim() != '');
}
- onInput($event,inputIdx){
- let newVal=this.hasVal(this.currentVal) ? `${this.currentVal}${$event.target.value}` : $event.target.value;
- if(this.config.allowNumbersOnly && !this.validateNumber(newVal)){
- $event.target.value=null;
+ onInput($event, inputIdx) {
+ let newVal = this.hasVal(this.currentVal) ? `${this.currentVal}${$event.target.value}` : $event.target.value;
+ if (this.config.allowNumbersOnly && !this.validateNumber(newVal)) {
+ $event.target.value = null;
$event.stopPropagation();
$event.preventDefault();
- this.clearInput(null,inputIdx);
+ this.clearInput(null, inputIdx);
return;
}
- if (this.ifValidKeyCode(null,$event.target.value)) {
+ if (this.ifValidKeyCode(null, $event.target.value)) {
const nextInputId = this.getBoxId(inputIdx + 1);
this.setSelected(nextInputId);
this.rebuildValue();
- }else{
- $event.target.value=null;
- let ctrlName=this.getControlName(inputIdx);
+ } else {
+ $event.target.value = null;
+ let ctrlName = this.getControlName(inputIdx);
this.otpForm.controls[ctrlName]?.setValue(null);
this.rebuildValue();
}
}
-
+
onKeyUp($event, inputIdx) {
- if(KeyboardUtil.ifTab($event)){
- inputIdx-=1;
+ if (KeyboardUtil.ifTab($event)) {
+ inputIdx -= 1;
}
const nextInputId = this.getBoxId(inputIdx + 1);
const prevInputId = this.getBoxId(inputIdx - 1);
@@ -205,26 +212,26 @@ export class NgOtpInputComponent implements OnInit, AfterViewInit,OnDestroy,Cont
}
}
- validateNumber(val){
+ validateNumber(val) {
return val && /^[0-9]+$/.test(val);
}
- getBoxId(idx:string | number){
+ getBoxId(idx: string | number) {
return `otp_${idx}_${this.componentKey}`;
}
- private clearInput(eleId:string,inputIdx){
- let ctrlName=this.getControlName(inputIdx);
+ private clearInput(eleId: string, inputIdx) {
+ let ctrlName = this.getControlName(inputIdx);
this.otpForm.controls[ctrlName]?.setValue(null);
- if(eleId){
- const ele=this.document.getElementById(eleId);
- if(ele && ele instanceof HTMLInputElement){
- ele.value=null;
+ if (eleId) {
+ const ele = this.document.getElementById(eleId);
+ if (ele && ele instanceof HTMLInputElement) {
+ ele.value = null;
}
}
}
- private setSelected(eleId) {
+ private setSelected(eleId) {
this.focusTo(eleId);
const ele: any = this.document.getElementById(eleId);
if (ele && ele.setSelectionRange) {
@@ -234,15 +241,15 @@ export class NgOtpInputComponent implements OnInit, AfterViewInit,OnDestroy,Cont
}
}
- private ifValidKeyCode(event,val?) {
- const inp =val??event.key;
- if(this.config?.allowNumbersOnly){
+ private ifValidKeyCode(event, val?) {
+ const inp = val ?? event.key;
+ if (this.config?.allowNumbersOnly) {
return this.validateNumber(inp);
}
const isMobile = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent);
return (
isMobile ||
- (/^[a-zA-Z0-9%*_\-@#$!]$/.test(inp) && inp.length==1)
+ (/^[a-zA-Z0-9%*_\-@#$!]$/.test(inp) && inp.length == 1)
);
}
@@ -256,77 +263,75 @@ export class NgOtpInputComponent implements OnInit, AfterViewInit,OnDestroy,Cont
// method to set component value
setValue(value: any) {
if (this.config.allowNumbersOnly && isNaN(value)) {
- return;
+ return;
}
this.otpForm?.reset();
- if (!this.hasVal(value)) {
- this.rebuildValue();
- return;
- }
- value = value.toString().replace(/\s/g, ''); // remove whitespace
- Array.from(value).forEach((c, idx) => {
- if (this.otpForm.get(this.getControlName(idx))) {
- this.otpForm.get(this.getControlName(idx)).setValue(c);
- }
- });
- if (!this.config.disableAutoFocus) {
+ if (!this.hasVal(value)) {
+ this.rebuildValue();
+ return;
+ }
+ value = value.toString().replace(/\s/g, ''); // remove whitespace
+ Array.from(value).forEach((c, idx) => {
+ if (this.otpForm.get(this.getControlName(idx))) {
+ this.otpForm.get(this.getControlName(idx)).setValue(c);
+ }
+ });
+ if (!this.config.disableAutoFocus) {
setTimeout(() => {
const containerItem = this.document.getElementById(`c_${this.componentKey}`);
var indexOfElementToFocus = value.length < this.config.length ? value.length : (this.config.length - 1);
- let ele : any = containerItem.getElementsByClassName('otp-input')[indexOfElementToFocus];
+ let ele: any = containerItem.getElementsByClassName('otp-input')[indexOfElementToFocus];
if (ele && ele.focus) {
setTimeout(() => {
ele.focus();
}, 1);
}
}, 0);
-
- }
- this.rebuildValue();
+
+ }
+ this.rebuildValue();
}
-private rebuildValue() {
+ private rebuildValue() {
let val = null;
ObjectUtil.keys(this.otpForm.controls).forEach(k => {
- let ctrlVal=this.otpForm.controls[k].value;
+ let ctrlVal = this.otpForm.controls[k].value;
if (ctrlVal) {
- let isLengthExceed=ctrlVal.length>1;
- let isCaseTransformEnabled= !this.config.allowNumbersOnly && this.config.letterCase && (this.config.letterCase.toLocaleLowerCase() == 'upper' || this.config.letterCase.toLocaleLowerCase()== 'lower');
- ctrlVal=ctrlVal[0];
- let transformedVal=isCaseTransformEnabled ? this.config.letterCase.toLocaleLowerCase() == 'upper' ? ctrlVal.toUpperCase() : ctrlVal.toLowerCase() : ctrlVal;
- if(isCaseTransformEnabled && transformedVal == ctrlVal){
- isCaseTransformEnabled=false;
- }else{
- ctrlVal=transformedVal;
+ let isLengthExceed = ctrlVal.length > 1;
+ let isCaseTransformEnabled = !this.config.allowNumbersOnly && this.config.letterCase && (this.config.letterCase.toLocaleLowerCase() == 'upper' || this.config.letterCase.toLocaleLowerCase() == 'lower');
+ ctrlVal = ctrlVal[0];
+ let transformedVal = isCaseTransformEnabled ? this.config.letterCase.toLocaleLowerCase() == 'upper' ? ctrlVal.toUpperCase() : ctrlVal.toLowerCase() : ctrlVal;
+ if (isCaseTransformEnabled && transformedVal == ctrlVal) {
+ isCaseTransformEnabled = false;
+ } else {
+ ctrlVal = transformedVal;
}
- if(val == null)
- {
- val=ctrlVal;
- }else{
+ if (val == null) {
+ val = ctrlVal;
+ } else {
val += ctrlVal;
}
- if(isLengthExceed || isCaseTransformEnabled)
- {
- this.otpForm.controls[k].setValue(ctrlVal);
+ if (isLengthExceed || isCaseTransformEnabled) {
+ this.otpForm.controls[k].setValue(ctrlVal);
}
}
});
- if(this.currentVal != val){
- this.currentVal=val;
- this.onChange(val);
- if(this.formCtrl?.setValue){
+ if (this.currentVal != val) {
+ this.currentVal = val;
+ this.onChange(val);
+ if (this.formCtrl?.setValue) {
this.formCtrl.setValue(val);
}
this.onInputChange.next(val);
}
}
-
-
+
+
handlePaste(e) {
// Get pasted data via clipboard API
let clipboardData = e.clipboardData || window['clipboardData'];
- if(clipboardData){
- var pastedData =clipboardData.getData('Text');
+ if (clipboardData) {
+ var pastedData = clipboardData.getData('Text');
}
e.stopPropagation();
e.preventDefault();
diff --git a/src/app/app.component.html b/src/app/app.component.html
index c1be5ea..eb6a087 100644
--- a/src/app/app.component.html
+++ b/src/app/app.component.html
@@ -22,6 +22,11 @@
Disabled
+
+
+ Show Error
+
Number of inputs
}>=new FormGroup({
- otp:new FormControl(null)
+ otp:new FormControl(null,[Validators.required])
});
otp: string;
showOtpComponent = true;