Skip to content

Commit

Permalink
Debounce TextControl if change runs immediately after input (#11985)
Browse files Browse the repository at this point in the history
  • Loading branch information
kgabryje authored Dec 9, 2020
1 parent a4b06d2 commit 6fe1f9d
Showing 1 changed file with 36 additions and 16 deletions.
52 changes: 36 additions & 16 deletions superset-frontend/src/explore/components/controls/TextControl.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import React from 'react';
import { FormGroup, FormControl } from 'react-bootstrap';
import { legacyValidateNumber, legacyValidateInteger } from '@superset-ui/core';
import debounce from 'lodash/debounce';
import ControlHeader from '../ControlHeader';

interface TextControlProps {
Expand All @@ -30,10 +31,12 @@ interface TextControlProps {
placeholder?: string;
value?: string | number;
controlId?: string;
renderTrigger?: boolean;
}

interface TextControlState {
controlId: string;
value?: string | number;
}

const generateControlId = (controlId?: string) =>
Expand All @@ -43,42 +46,59 @@ export default class TextControl extends React.Component<
TextControlProps,
TextControlState
> {
debouncedOnChange = debounce((inputValue: string) => {
this.onChange(inputValue);
}, 500);

constructor(props: TextControlProps) {
super(props);
this.onChange = this.onChange.bind(this);

// if there's no control id provided, generate a random
// number to prevent rendering elements with same ids
this.state = {
controlId: generateControlId(props.controlId),
value: props.value,
};
}

onChange(event: any) {
let { value } = event.target;

onChange = (inputValue: string) => {
let parsedValue: string | number = inputValue;
// Validation & casting
const errors = [];
if (value !== '' && this.props.isFloat) {
const error = legacyValidateNumber(value);
if (inputValue !== '' && this.props.isFloat) {
const error = legacyValidateNumber(inputValue);
if (error) {
errors.push(error);
} else {
value = value.match(/.*([.0])$/g) ? value : parseFloat(value);
parsedValue = inputValue.match(/.*([.0])$/g)
? inputValue
: parseFloat(inputValue);
}
}
if (value !== '' && this.props.isInt) {
const error = legacyValidateInteger(value);
if (inputValue !== '' && this.props.isInt) {
const error = legacyValidateInteger(inputValue);
if (error) {
errors.push(error);
} else {
value = parseInt(value, 10);
parsedValue = parseInt(inputValue, 10);
}
}
this.props.onChange?.(value, errors);
}
this.props.onChange?.(parsedValue, errors);
};

onChangeWrapper = (event: any) => {
const { value } = event.target;
this.setState({ value });

render() {
const { value: rawValue } = this.props;
// use debounce when change takes effect immediately after user starts typing
const onChange = this.props.renderTrigger
? this.debouncedOnChange
: this.onChange;
onChange(value);
};

render = () => {
const { value: rawValue } = this.state;
const value =
typeof rawValue !== 'undefined' && rawValue !== null
? rawValue.toString()
Expand All @@ -92,13 +112,13 @@ export default class TextControl extends React.Component<
type="text"
data-test="inline-name"
placeholder={this.props.placeholder}
onChange={this.onChange}
onChange={this.onChangeWrapper}
onFocus={this.props.onFocus}
value={value}
disabled={this.props.disabled}
/>
</FormGroup>
</div>
);
}
};
}

0 comments on commit 6fe1f9d

Please sign in to comment.