mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-11-07 23:16:52 +08:00
feat(input-otp): add new input-otp component (#30386)
Adds a new component `ion-input-otp` which provides the OTP input functionality - Displays as an input group with multiple boxes accepting a single character - Accepts `type` which determines whether the boxes accept numbers or text/numbers and determines the keyboard to display - Supports changing the displayed keyboard using the `inputmode` property - Accepts a `length` property to control the number of input boxes - Accepts the following properties to change the design: `fill`, `shape`, `size`, `color` - Accepts a `separators` property to show a separator between 1 or more input boxes - Supports the `disabled`, `readonly` and invalid states - Supports limiting the accepted input via the `pattern` property - Emits the following events: `ionInput`, `ionChange`, `ionComplete`, `ionBlur`, `ionFocus` - Exposes the following method: `setFocus` --------- Co-authored-by: Brandy Smith <6577830+brandyscarney@users.noreply.github.com> Co-authored-by: Shane <shane@shanessite.net>
This commit is contained in:
@ -44,6 +44,20 @@
|
||||
<ion-input label="Input" formControlName="input2"></ion-input>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-input-otp id="touched-input-otp-number-test" formControlName="inputOtp" class="required">Input OTP (required)</ion-input-otp>
|
||||
</ion-item>
|
||||
|
||||
<ion-button id="input-otp-touched" (click)="setOtpTouched()">Set Input OTP Touched</ion-button>
|
||||
|
||||
<ion-item>
|
||||
<ion-input-otp id="touched-input-otp-text-test" type="text" formControlName="inputOtpText" class="required">Input OTP Text (required)</ion-input-otp>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-input-otp formControlName="inputOtp2">Input OTP</ion-input-otp>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-checkbox formControlName="checkbox"> Checkbox </ion-checkbox>
|
||||
</ion-item>
|
||||
|
||||
@ -1,6 +1,15 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { UntypedFormGroup, UntypedFormBuilder, Validators, UntypedFormControl } from '@angular/forms';
|
||||
import { UntypedFormGroup, UntypedFormBuilder, Validators, UntypedFormControl, AbstractControl, ValidationErrors } from '@angular/forms';
|
||||
|
||||
function otpRequiredLength(length: number) {
|
||||
return (control: AbstractControl): ValidationErrors | null => {
|
||||
const value = control.value;
|
||||
if (!value || value.toString().length !== length) {
|
||||
return { otpLength: true };
|
||||
}
|
||||
return null;
|
||||
};
|
||||
}
|
||||
@Component({
|
||||
selector: 'app-form',
|
||||
templateUrl: './form.component.html',
|
||||
@ -19,6 +28,9 @@ export class FormComponent {
|
||||
toggle: [false],
|
||||
input: ['', Validators.required],
|
||||
input2: ['Default Value'],
|
||||
inputOtp: [null, [Validators.required, otpRequiredLength(4)]],
|
||||
inputOtpText: ['', [Validators.required, otpRequiredLength(4)]],
|
||||
inputOtp2: [1234],
|
||||
inputMin: [1, Validators.min(1)],
|
||||
inputMax: [1, Validators.max(1)],
|
||||
checkbox: [false],
|
||||
@ -35,6 +47,13 @@ export class FormComponent {
|
||||
}
|
||||
}
|
||||
|
||||
setOtpTouched() {
|
||||
const formControl = this.profileForm.get('inputOtp');
|
||||
if (formControl) {
|
||||
formControl.markAsTouched();
|
||||
}
|
||||
}
|
||||
|
||||
onSubmit() {
|
||||
this.submitted = 'true';
|
||||
}
|
||||
@ -46,6 +65,9 @@ export class FormComponent {
|
||||
toggle: true,
|
||||
input: 'Some value',
|
||||
input2: 'Another values',
|
||||
inputOtp: 5678,
|
||||
inputOtpText: 'ABCD',
|
||||
inputOtp2: 1234,
|
||||
checkbox: true,
|
||||
radio: 'nes'
|
||||
});
|
||||
|
||||
@ -71,6 +71,16 @@
|
||||
<ion-note slot="end">{{input}}</ion-note>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-input-otp [(ngModel)]="inputOtp">Input OTP</ion-input-otp>
|
||||
<ion-note slot="end" id="input-otp-note">{{inputOtp}}</ion-note>
|
||||
</ion-item>
|
||||
|
||||
<ion-item color="dark">
|
||||
<ion-input-otp [(ngModel)]="inputOtp">Input OTP Mirror</ion-input-otp>
|
||||
<ion-note slot="end">{{inputOtp}}</ion-note>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-checkbox [(ngModel)]="checkbox" slot="start" id="first-checkbox">
|
||||
Checkbox
|
||||
|
||||
@ -9,6 +9,7 @@ export class InputsComponent {
|
||||
|
||||
datetime? = '1994-03-15';
|
||||
input? = 'some text';
|
||||
inputOtp? = '1234';
|
||||
checkbox = true;
|
||||
radio? = 'nes';
|
||||
toggle = true;
|
||||
@ -20,6 +21,7 @@ export class InputsComponent {
|
||||
console.log('set values');
|
||||
this.datetime = '1994-03-15';
|
||||
this.input = 'some text';
|
||||
this.inputOtp = '1234';
|
||||
this.checkbox = true;
|
||||
this.radio = 'nes';
|
||||
this.toggle = true;
|
||||
@ -31,6 +33,7 @@ export class InputsComponent {
|
||||
console.log('reset values');
|
||||
this.datetime = undefined;
|
||||
this.input = undefined;
|
||||
this.inputOtp = undefined;
|
||||
this.checkbox = false;
|
||||
this.radio = undefined;
|
||||
this.toggle = false;
|
||||
|
||||
@ -44,6 +44,7 @@ export const routes: Routes = [
|
||||
{ path: 'checkbox', loadComponent: () => import('../value-accessors/checkbox/checkbox.component').then(c => c.CheckboxComponent) },
|
||||
{ path: 'datetime', loadComponent: () => import('../value-accessors/datetime/datetime.component').then(c => c.DatetimeComponent) },
|
||||
{ path: 'input', loadComponent: () => import('../value-accessors/input/input.component').then(c => c.InputComponent) },
|
||||
{ path: 'input-otp', loadComponent: () => import('../value-accessors/input-otp/input-otp.component').then(c => c.InputOtpComponent) },
|
||||
{ path: 'radio-group', loadComponent: () => import('../value-accessors/radio-group/radio-group.component').then(c => c.RadioGroupComponent) },
|
||||
{ path: 'range', loadComponent: () => import('../value-accessors/range/range.component').then(c => c.RangeComponent) },
|
||||
{ path: 'searchbar', loadComponent: () => import('../value-accessors/searchbar/searchbar.component').then(c => c.SearchbarComponent) },
|
||||
|
||||
@ -116,6 +116,11 @@
|
||||
Input Test
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
<ion-item routerLink="/standalone/value-accessors/input-otp">
|
||||
<ion-label>
|
||||
Input OTP Test
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
<ion-item routerLink="/standalone/value-accessors/radio-group">
|
||||
<ion-label>
|
||||
Radio Group Test
|
||||
|
||||
@ -0,0 +1,11 @@
|
||||
<div>
|
||||
<h1>IonInputOtp Value Accessors</h1>
|
||||
<p>
|
||||
This test checks the form integrations with ion-input-otp to make sure values are correctly assigned to the form group.
|
||||
</p>
|
||||
|
||||
<app-value-accessor-test [formGroup]="form">
|
||||
<ion-input-otp type="text" formControlName="inputOtpString">String</ion-input-otp>
|
||||
<ion-input-otp type="number" formControlName="inputOtpNumber">Number</ion-input-otp>
|
||||
</app-value-accessor-test>
|
||||
</div>
|
||||
@ -0,0 +1,34 @@
|
||||
import { Component } from "@angular/core";
|
||||
import { FormBuilder, FormsModule, ReactiveFormsModule, Validators, AbstractControl, ValidationErrors } from "@angular/forms";
|
||||
import { IonInputOtp } from "@ionic/angular/standalone";
|
||||
import { ValueAccessorTestComponent } from "../value-accessor-test/value-accessor-test.component";
|
||||
|
||||
function otpRequiredLength(length: number) {
|
||||
return (control: AbstractControl): ValidationErrors | null => {
|
||||
const value = control.value;
|
||||
if (!value || value.toString().length !== length) {
|
||||
return { otpLength: true };
|
||||
}
|
||||
return null;
|
||||
};
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'app-input-otp',
|
||||
templateUrl: 'input-otp.component.html',
|
||||
standalone: true,
|
||||
imports: [
|
||||
IonInputOtp,
|
||||
ReactiveFormsModule,
|
||||
FormsModule,
|
||||
ValueAccessorTestComponent
|
||||
]
|
||||
})
|
||||
export class InputOtpComponent {
|
||||
form = this.fb.group({
|
||||
inputOtpString: ['', [Validators.required, otpRequiredLength(4)]],
|
||||
inputOtpNumber: ['', [Validators.required, otpRequiredLength(4)]],
|
||||
});
|
||||
|
||||
constructor(private fb: FormBuilder) { }
|
||||
}
|
||||
Reference in New Issue
Block a user