[explorev2] Fields can validate input and handle errors (#1980)
As a result here, TextField does its own validation and now casts the values it sends to Int or Float if set to do so.
This commit is contained in:
parent
99b84d2909
commit
a96024d0e7
|
|
@ -42,8 +42,11 @@ export default class FieldSet extends React.PureComponent {
|
|||
this.validate = this.validate.bind(this);
|
||||
this.onChange = this.onChange.bind(this);
|
||||
}
|
||||
onChange(value) {
|
||||
const validationErrors = this.validate(value);
|
||||
onChange(value, errors) {
|
||||
let validationErrors = this.validate(value);
|
||||
if (errors && errors.length > 0) {
|
||||
validationErrors = validationErrors.concat(errors);
|
||||
}
|
||||
this.props.actions.setFieldValue(this.props.name, value, validationErrors);
|
||||
}
|
||||
validate(value) {
|
||||
|
|
|
|||
|
|
@ -1,12 +1,18 @@
|
|||
import React, { PropTypes } from 'react';
|
||||
import { FormGroup, FormControl } from 'react-bootstrap';
|
||||
import * as v from '../validators';
|
||||
|
||||
const propTypes = {
|
||||
name: PropTypes.string.isRequired,
|
||||
label: PropTypes.string,
|
||||
description: PropTypes.string,
|
||||
onChange: PropTypes.func,
|
||||
value: PropTypes.string,
|
||||
value: PropTypes.oneOf([
|
||||
PropTypes.string,
|
||||
PropTypes.number,
|
||||
]),
|
||||
isFloat: PropTypes.bool,
|
||||
isInt: PropTypes.bool,
|
||||
};
|
||||
|
||||
const defaultProps = {
|
||||
|
|
@ -14,21 +20,49 @@ const defaultProps = {
|
|||
description: null,
|
||||
onChange: () => {},
|
||||
value: '',
|
||||
isInt: false,
|
||||
isFloat: false,
|
||||
};
|
||||
|
||||
export default class TextField extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
const value = props.value ? props.value.toString() : '';
|
||||
this.state = { value };
|
||||
this.onChange = this.onChange.bind(this);
|
||||
}
|
||||
onChange(event) {
|
||||
this.props.onChange(event.target.value);
|
||||
let value = event.target.value || '';
|
||||
this.setState({ value });
|
||||
|
||||
// Validation & casting
|
||||
const errors = [];
|
||||
if (this.props.isFloat) {
|
||||
const error = v.numeric(value);
|
||||
if (error) {
|
||||
errors.push(error);
|
||||
} else {
|
||||
value = parseFloat(value);
|
||||
}
|
||||
}
|
||||
if (this.props.isInt) {
|
||||
const error = v.integer(value);
|
||||
if (error) {
|
||||
errors.push(error);
|
||||
} else {
|
||||
value = parseInt(value, 10);
|
||||
}
|
||||
}
|
||||
this.props.onChange(value, errors);
|
||||
}
|
||||
render() {
|
||||
const value = this.props.value || '';
|
||||
return (
|
||||
<FormGroup controlId="formInlineName" bsSize="small">
|
||||
<FormControl
|
||||
type="text"
|
||||
placeholder=""
|
||||
onChange={this.onChange.bind(this)}
|
||||
value={value}
|
||||
onChange={this.onChange}
|
||||
value={this.state.value}
|
||||
/>
|
||||
</FormGroup>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -514,7 +514,7 @@ export const fields = {
|
|||
treemap_ratio: {
|
||||
type: 'TextField',
|
||||
label: 'Ratio',
|
||||
validators: [v.numeric],
|
||||
isFloat: true,
|
||||
default: 0.5 * (1 + Math.sqrt(5)), // d3 default, golden ratio
|
||||
description: 'Target aspect ratio for treemap tiles.',
|
||||
},
|
||||
|
|
@ -567,7 +567,7 @@ export const fields = {
|
|||
rolling_periods: {
|
||||
type: 'TextField',
|
||||
label: 'Periods',
|
||||
validators: [v.integer],
|
||||
isInt: true,
|
||||
description: 'Defines the size of the rolling window function, ' +
|
||||
'relative to the time granularity selected',
|
||||
},
|
||||
|
|
@ -666,7 +666,7 @@ export const fields = {
|
|||
compare_lag: {
|
||||
type: 'TextField',
|
||||
label: 'Comparison Period Lag',
|
||||
validators: [v.integer],
|
||||
isInt: true,
|
||||
description: 'Based on granularity, number of time periods to compare against',
|
||||
},
|
||||
|
||||
|
|
@ -793,7 +793,7 @@ export const fields = {
|
|||
|
||||
size_from: {
|
||||
type: 'TextField',
|
||||
validators: [v.integer],
|
||||
isInt: true,
|
||||
label: 'Font Size From',
|
||||
default: '20',
|
||||
description: 'Font size for the smallest value in the list',
|
||||
|
|
@ -801,7 +801,7 @@ export const fields = {
|
|||
|
||||
size_to: {
|
||||
type: 'TextField',
|
||||
validators: [v.integer],
|
||||
isInt: true,
|
||||
label: 'Font Size To',
|
||||
default: '150',
|
||||
description: 'Font size for the biggest value in the list',
|
||||
|
|
@ -917,7 +917,7 @@ export const fields = {
|
|||
type: 'TextField',
|
||||
label: 'Period Ratio',
|
||||
default: '',
|
||||
validators: [v.integer],
|
||||
isInt: true,
|
||||
description: '[integer] Number of period to compare against, ' +
|
||||
'this is relative to the granularity selected',
|
||||
},
|
||||
|
|
@ -934,7 +934,7 @@ export const fields = {
|
|||
time_compare: {
|
||||
type: 'TextField',
|
||||
label: 'Time Shift',
|
||||
validators: [v.integer],
|
||||
isInt: true,
|
||||
default: null,
|
||||
description: 'Overlay a timeseries from a ' +
|
||||
'relative time period. Expects relative time delta ' +
|
||||
|
|
@ -1022,7 +1022,7 @@ export const fields = {
|
|||
type: 'TextField',
|
||||
label: 'Opacity',
|
||||
default: 1,
|
||||
validators: [v.numeric],
|
||||
isFloat: true,
|
||||
description: 'Opacity of all clusters, points, and labels. ' +
|
||||
'Between 0 and 1.',
|
||||
},
|
||||
|
|
@ -1030,7 +1030,7 @@ export const fields = {
|
|||
viewport_zoom: {
|
||||
type: 'TextField',
|
||||
label: 'Zoom',
|
||||
validators: [v.numeric],
|
||||
isFloat: true,
|
||||
default: 11,
|
||||
description: 'Zoom level of the map',
|
||||
places: 8,
|
||||
|
|
@ -1040,7 +1040,7 @@ export const fields = {
|
|||
type: 'TextField',
|
||||
label: 'Default latitude',
|
||||
default: 37.772123,
|
||||
validators: [v.numeric],
|
||||
isFloat: true,
|
||||
description: 'Latitude of default viewport',
|
||||
places: 8,
|
||||
},
|
||||
|
|
@ -1049,7 +1049,7 @@ export const fields = {
|
|||
type: 'TextField',
|
||||
label: 'Default longitude',
|
||||
default: -122.405293,
|
||||
validators: [v.numeric],
|
||||
isFloat: true,
|
||||
description: 'Longitude of default viewport',
|
||||
places: 8,
|
||||
},
|
||||
|
|
|
|||
Loading…
Reference in New Issue