mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-22 05:21:52 +08:00
feat(inputs) debounce input and change events (#13764)
* feat(helpers) add debounce helper * feat(searchbar) debounce ionInput * feat(range) debounce ionChange * feat(input) debouce ionInput * feat(textarea) debounce ionInput * feat(range) make debounceChange private * feat(searchbar) make debounceInput private * feat(inputs) change default debounce to 0 in input/textarea
This commit is contained in:
2
packages/core/src/components.d.ts
vendored
2
packages/core/src/components.d.ts
vendored
@ -1155,6 +1155,7 @@ declare global {
|
||||
checked?: boolean;
|
||||
clearInput?: boolean;
|
||||
clearOnEdit?: boolean;
|
||||
debounce?: number;
|
||||
disabled?: boolean;
|
||||
inputmode?: string;
|
||||
max?: string;
|
||||
@ -2880,6 +2881,7 @@ declare global {
|
||||
autofocus?: boolean;
|
||||
clearOnEdit?: boolean;
|
||||
cols?: number;
|
||||
debounce?: number;
|
||||
disabled?: boolean;
|
||||
maxlength?: number;
|
||||
minlength?: number;
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { Component, Element, Event, EventEmitter, Prop, PropDidChange } from '@stencil/core';
|
||||
|
||||
import { debounce } from '../../utils/helpers';
|
||||
import { createThemedClasses } from '../../utils/theme';
|
||||
import { InputComponent } from './input-base';
|
||||
|
||||
@ -23,6 +24,11 @@ export class Input implements InputComponent {
|
||||
|
||||
@Element() private el: HTMLElement;
|
||||
|
||||
/**
|
||||
* @output {Event} Emitted when the input value has changed.
|
||||
*/
|
||||
@Event() ionInput: EventEmitter;
|
||||
|
||||
/**
|
||||
* @output {Event} Emitted when the styles change.
|
||||
*/
|
||||
@ -83,6 +89,18 @@ export class Input implements InputComponent {
|
||||
*/
|
||||
@Prop({ mutable: true }) clearOnEdit: boolean;
|
||||
|
||||
/**
|
||||
* @input {number} Set the amount of time, in milliseconds, to wait to trigger the `ionInput` event after each keystroke. Default `0`.
|
||||
*/
|
||||
@Prop() debounce: number = 0;
|
||||
@PropDidChange('debounce')
|
||||
private debounceInput() {
|
||||
this.ionInput.emit = debounce(
|
||||
this.ionInput.emit.bind(this.ionInput),
|
||||
this.debounce
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @input {boolean} If true, the user cannot interact with the input. Defaults to `false`.
|
||||
*/
|
||||
@ -192,6 +210,7 @@ export class Input implements InputComponent {
|
||||
|
||||
|
||||
componentDidLoad() {
|
||||
this.debounceInput();
|
||||
this.emitStyle();
|
||||
|
||||
// By default, password inputs clear after focus when they have content
|
||||
@ -225,6 +244,7 @@ export class Input implements InputComponent {
|
||||
|
||||
inputChanged(ev: any) {
|
||||
this.value = ev.target && ev.target.value;
|
||||
this.ionInput.emit(ev);
|
||||
this.emitStyle();
|
||||
}
|
||||
|
||||
@ -242,15 +262,15 @@ export class Input implements InputComponent {
|
||||
}
|
||||
}
|
||||
|
||||
inputKeydown() {
|
||||
this.checkClearOnEdit();
|
||||
inputKeydown(ev: any) {
|
||||
this.checkClearOnEdit(ev);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check if we need to clear the text input if clearOnEdit is enabled
|
||||
*/
|
||||
checkClearOnEdit() {
|
||||
checkClearOnEdit(ev: any) {
|
||||
if (!this.clearOnEdit) {
|
||||
return;
|
||||
}
|
||||
@ -258,15 +278,16 @@ export class Input implements InputComponent {
|
||||
// Did the input value change after it was blurred and edited?
|
||||
if (this.didBlurAfterEdit && this.hasValue()) {
|
||||
// Clear the input
|
||||
this.clearTextInput();
|
||||
this.clearTextInput(ev);
|
||||
}
|
||||
|
||||
// Reset the flag
|
||||
this.didBlurAfterEdit = false;
|
||||
}
|
||||
|
||||
clearTextInput() {
|
||||
clearTextInput(ev: any) {
|
||||
this.value = '';
|
||||
this.ionInput.emit(ev);
|
||||
}
|
||||
|
||||
hasFocus(): boolean {
|
||||
|
@ -47,6 +47,11 @@ boolean
|
||||
boolean
|
||||
|
||||
|
||||
#### debounce
|
||||
|
||||
number
|
||||
|
||||
|
||||
#### disabled
|
||||
|
||||
boolean
|
||||
@ -179,6 +184,11 @@ boolean
|
||||
boolean
|
||||
|
||||
|
||||
#### debounce
|
||||
|
||||
number
|
||||
|
||||
|
||||
#### disabled
|
||||
|
||||
boolean
|
||||
@ -277,6 +287,9 @@ string
|
||||
#### ionFocus
|
||||
|
||||
|
||||
#### ionInput
|
||||
|
||||
|
||||
#### ionStyle
|
||||
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { Component, Element, Event, EventEmitter, Listen, Method, Prop, PropDidChange, State } from '@stencil/core';
|
||||
import { BaseInputComponent, GestureDetail } from '../../index';
|
||||
import { clamp } from '../../utils/helpers';
|
||||
import { clamp, debounce } from '../../utils/helpers';
|
||||
|
||||
@Component({
|
||||
tag: 'ion-range',
|
||||
@ -75,6 +75,13 @@ export class Range implements BaseInputComponent {
|
||||
* `ionChange` event after each change in the range value. Default `0`.
|
||||
*/
|
||||
@Prop() debounce: number = 0;
|
||||
@PropDidChange('debounce')
|
||||
private debounceChange() {
|
||||
this.ionChange.emit = debounce(
|
||||
this.ionChange.emit.bind(this.ionChange),
|
||||
this.debounce
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* @input {boolean} If true, the user cannot interact with the range. Default false.
|
||||
@ -126,13 +133,14 @@ export class Range implements BaseInputComponent {
|
||||
|
||||
@PropDidChange('value')
|
||||
protected valueChanged(val: boolean) {
|
||||
setTimeout(() => this.ionChange.emit({value: val}), this.debounce);
|
||||
this.ionChange.emit({value: val});
|
||||
this.emitStyle();
|
||||
}
|
||||
|
||||
componentWillLoad() {
|
||||
this.inputUpdated();
|
||||
this.createTicks();
|
||||
this.debounceChange();
|
||||
this.emitStyle();
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { Component, Element, Event, EventEmitter, Prop, State } from '@stencil/core';
|
||||
import { Component, Element, Event, EventEmitter, Prop, PropDidChange, State } from '@stencil/core';
|
||||
import { debounce } from '../../utils/helpers';
|
||||
|
||||
|
||||
@Component({
|
||||
@ -86,6 +87,13 @@ export class Searchbar {
|
||||
* @input {number} Set the amount of time, in milliseconds, to wait to trigger the `ionInput` event after each keystroke. Default `250`.
|
||||
*/
|
||||
@Prop({ mutable: true }) debounce: number = 250;
|
||||
@PropDidChange('debounce')
|
||||
private debounceInput() {
|
||||
this.ionInput.emit = debounce(
|
||||
this.ionInput.emit.bind(this.ionInput),
|
||||
this.debounce
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @input {string} Set the input's placeholder. Default `"Search"`.
|
||||
@ -115,6 +123,7 @@ export class Searchbar {
|
||||
|
||||
componentDidLoad() {
|
||||
this.positionElements();
|
||||
this.debounceInput();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -153,9 +162,7 @@ export class Searchbar {
|
||||
*/
|
||||
inputChanged(ev: any) {
|
||||
this.value = ev.target.value;
|
||||
setTimeout(() => {
|
||||
this.ionInput.emit(ev);
|
||||
}, this.debounce);
|
||||
}
|
||||
|
||||
inputUpdated() {
|
||||
|
@ -66,6 +66,11 @@ boolean
|
||||
number
|
||||
|
||||
|
||||
#### debounce
|
||||
|
||||
number
|
||||
|
||||
|
||||
#### disabled
|
||||
|
||||
boolean
|
||||
@ -148,6 +153,11 @@ boolean
|
||||
number
|
||||
|
||||
|
||||
#### debounce
|
||||
|
||||
number
|
||||
|
||||
|
||||
#### disabled
|
||||
|
||||
boolean
|
||||
@ -211,6 +221,9 @@ string
|
||||
#### ionFocus
|
||||
|
||||
|
||||
#### ionInput
|
||||
|
||||
|
||||
#### ionStyle
|
||||
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { Component, Element, Event, EventEmitter, Prop, PropDidChange } from '@stencil/core';
|
||||
|
||||
import { debounce } from '../../utils/helpers';
|
||||
import { createThemedClasses } from '../../utils/theme';
|
||||
import { TextareaComponent } from '../input/input-base';
|
||||
|
||||
@ -29,6 +30,11 @@ export class Textarea implements TextareaComponent {
|
||||
|
||||
@Element() private el: HTMLElement;
|
||||
|
||||
/**
|
||||
* @output {Event} Emitted when the input value has changed.
|
||||
*/
|
||||
@Event() ionInput: EventEmitter;
|
||||
|
||||
/**
|
||||
* @output {Event} Emitted when the styles change.
|
||||
*/
|
||||
@ -64,6 +70,18 @@ export class Textarea implements TextareaComponent {
|
||||
*/
|
||||
@Prop({ mutable: true }) clearOnEdit: boolean;
|
||||
|
||||
/**
|
||||
* @input {number} Set the amount of time, in milliseconds, to wait to trigger the `ionInput` event after each keystroke. Default `0`.
|
||||
*/
|
||||
@Prop() debounce: number = 0;
|
||||
@PropDidChange('debounce')
|
||||
private debounceInput() {
|
||||
this.ionInput.emit = debounce(
|
||||
this.ionInput.emit.bind(this.ionInput),
|
||||
this.debounce
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @input {boolean} If true, the user cannot interact with the textarea. Defaults to `false`.
|
||||
*/
|
||||
@ -141,6 +159,7 @@ export class Textarea implements TextareaComponent {
|
||||
}
|
||||
|
||||
componentDidLoad() {
|
||||
this.debounceInput();
|
||||
this.emitStyle();
|
||||
}
|
||||
|
||||
@ -160,8 +179,9 @@ export class Textarea implements TextareaComponent {
|
||||
});
|
||||
}
|
||||
|
||||
clearTextInput() {
|
||||
clearTextInput(ev: any) {
|
||||
this.value = '';
|
||||
this.ionInput.emit(ev);
|
||||
}
|
||||
|
||||
inputBlurred(ev: any) {
|
||||
@ -173,6 +193,7 @@ export class Textarea implements TextareaComponent {
|
||||
|
||||
inputChanged(ev: any) {
|
||||
this.value = ev.target && ev.target.value;
|
||||
this.ionInput.emit(ev);
|
||||
this.emitStyle();
|
||||
}
|
||||
|
||||
@ -183,14 +204,14 @@ export class Textarea implements TextareaComponent {
|
||||
this.emitStyle();
|
||||
}
|
||||
|
||||
inputKeydown() {
|
||||
this.checkClearOnEdit();
|
||||
inputKeydown(ev: any) {
|
||||
this.checkClearOnEdit(ev);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if we need to clear the text input if clearOnEdit is enabled
|
||||
*/
|
||||
checkClearOnEdit() {
|
||||
checkClearOnEdit(ev: any) {
|
||||
if (!this.clearOnEdit) {
|
||||
return;
|
||||
}
|
||||
@ -198,7 +219,7 @@ export class Textarea implements TextareaComponent {
|
||||
// Did the input value change after it was blurred and edited?
|
||||
if (this.didBlurAfterEdit && this.hasValue()) {
|
||||
// Clear the input
|
||||
this.clearTextInput();
|
||||
this.clearTextInput(ev);
|
||||
}
|
||||
|
||||
// Reset the flag
|
||||
|
@ -295,3 +295,11 @@ export function domControllerAsync(domControllerFunction: Function, callback?: F
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export function debounce(func: Function, wait: number = 250) {
|
||||
let timer: number;
|
||||
return (...args: any[]): void => {
|
||||
clearTimeout(timer);
|
||||
timer = setTimeout(func, wait, ...args);
|
||||
};
|
||||
}
|
||||
|
Reference in New Issue
Block a user