admin-on-rest, redux-form, and trimming field valu

2019-04-09 14:30发布

问题:

This is actually less a question than it is me sharing my technique for trimming field values using this library. I'd read every single posting I could find on the matter on Stack Exchange and elsewhere, and could not find a complete working solution. It took me too much time and some trial and error to figure out.

With redux-form you must use the change action creator to reset the field value to the trimmed value. The hard part was finding the right place in the code under the right conditions to do the trim and fire the action. I tried the normalize method included with redux-form. No. I tried trimming in custom onChange and onBlur handlers on the fields. No. Most attempted solutions resulted in an inability to type a space in the field. I thought I could get it done in a custom onBlur handler, but if I dispatched a redux-form change action from within that handler then the change action updated the state first, then the pending blur action followed and would overwrite the trimmed value with the original value in the state.

Anyway, here's my solution.

1) Import the redux-form change action and add custom method to your props to dispatch it.

import { connect } from 'react-redux';
import { change } from 'redux-form';

const form = 'record-form';

function mapDispatchToProps(dispatch) {
    return {
        trimFieldValue: (field, value) => {
            dispatch(change(form, field, value.trim()));
        },
    };
}
const enhance = connect(null, mapDispatchToProps);
export default enhance(MyComponent);

2) Keep track of field focus in the local state, add onFocus and onBlur handlers to fields that need to be trimmed.

in the render method...

    const handleBlur = (event) => {
        this.setState({
            hasFocus: null
        });
    }

    const handleFocus = (event) => {
        this.setState({
            hasFocus: event.target.name
        });
    }

in the JSX...

<LongTextInput source="name" onBlur={handleBlur} onFocus={handleFocus} />
<LongTextInput source="description" onBlur={handleBlur} onFocus={handleFocus} />

3) Inspect for the need to trim values componentDidUpdate() and dispatch the action to do so if necessary.

componentDidUpdate = (prevProps, prevState) => {
    if (this.state && this.state.name && this.state.hasFocus !== 'name' && (this.state.name !== this.state.name.trim())) {
        this.props.trimFieldValue('name', this.state.name);
    }
    if (this.state && this.state.description && this.state.hasFocus !== 'description' && (this.state.description !== this.state.description.trim())) {
        this.props.trimFieldValue('description', this.state.description);
    }
}

My componentDidUpdate method is a little ugly, but it works for now. The gist of it is that for each field you're testing to trim, you need to do nothing if that field has focus. If the field does not have focus, and it should be trimmed, then fire off the action to update that field in the redux form using your custom dispatcher in the props.

Maybe it should not have taken me so long, but I found this solution not an easy one to figure out. Maybe this approach will save someone else some time. I'm also open to feedback along the lines of "uh, why didn't you just do this!" if there's something I missed.