React-redux-form: Issues getting Control.select to work with material-ui SelectField

Created on 31 Jan 2017  路  8Comments  路  Source: davidkpiano/react-redux-form

I'm working to get Control.select to work w/ http://www.material-ui.com/#/components/select-field. I feel as though there seems to be a disconnect b/w the parent component and the MenuItem children. It seems as though the value, props.modelValue is not being updated properly causing the proper MenuItem to become selected. You can see in the screenshot below, the model value is being set properly, but the dropdown does not have any MenuItem selected.

Has anyone done this before or could fill me in on something that I might be missing?

screen shot 2017-01-31 at 1 22 05 pm

<Control.select model='.attributes.platform'
                           component={SelectField}
                           onChange={this.setPlatform}
                           mapProps={{
                             value: (props) => props.modelValue,
                           }}>
  <MenuItem value='ios' primaryText='iOS' />
  <MenuItem value='android' primaryText='Android' />
  <MenuItem value='windows' primaryText='Windows' />
  <MenuItem value='amazon' primaryText='Amazon' />
  <MenuItem value='web' primaryText='Web' />
</Control.select>

Most helpful comment

@davidkpiano In handleResolutionChange, I dispatch actions.change.

... but here's an even better way that does not require custom onChange handlers:

// Curried function that basically transforms Material-UI's onChange function
// into a react-redux-form dispatch(action.change) function.
const handleChange = ({ model, dispatch }, options = {}) =>
  (ev, index, value) =>
    dispatch(actions.change(model, value, options));

<Control.select
  model={`forms.overlay.panels[${index}].css.backgroundRepeat`}
  component={SelectField}
  mapProps={{
    floatingLabelText: 'Repeating',
    onChange: (props) => handleChange(props),
  }}
>
  <MenuItem value="repeat" primaryText="Repeat" />
  <MenuItem value="repeat-x" primaryText="Repeat horizontally" />
  <MenuItem value="repeat-y" primaryText="Repeat vertically" />
  <MenuItem value="no-repeat" primaryText="No repeating" />
</Control.select>

All 8 comments

Can you set up a working example on www.esnextb.in ?

Also, does it work if you omit onChange and mapProps in <Control.select>?

Omitting onChange and mapProps didn't do anything, it actually didn't even set the value in the store.

So looks as though, esnextbin relies on https://wzrd.in, which seems to be down, throwing a 502.

Let me try to get something on jsbin, unless you have any other thoughts on potentially why this isn't working.

I have the same issue I think, or at least similar, and also with DropDownMenu from material-ui.

The rff/change event that is dispatched has a value of "undefined" (onChange and mapProps ommitted). The model string is correct though.

@dasnixon , what does your setPlatform function look like? I'm pretty new to all this so could use some examples.

At the very least, try dispatch(actions.change(model, value)) inside the SelectField's onChange={...} prop (same with DropDownMenu).

Remember: you _don't_ need to use <Control> - you can dispatch actions and read from the state manually. See if that works first.

@Finlorfin I wasn't able to get it working with the Control.select, so I ended up SelectField from material-ui and handling the validation "manually". Hope it helps.

// This is my visual component that is connected with a container
export default class CreateApp extends Component {

  constructor() {
    super(...arguments);
    this.props.validatePlatform();
  }

  setPlatform = (ev, index, value) => this.props.setPlatform(value);

  <SelectField value={this.props.platform}
                        onChange={this.setPlatform}
                      fullWidth={true}
                      floatingLabelText='Platform'>
    <MenuItem value='' primaryText='' />
    <MenuItem value='ios' primaryText='iOS' />
    <MenuItem value='android' primaryText='Android' />
    <MenuItem value='windows' primaryText='Windows' />
    <MenuItem value='amazon' primaryText='Amazon' />
    <MenuItem value='web' primaryText='Web' />
  </SelectField>

  <Errors className='errors'
                model='.attributes.platform'
                show='touched'
                messages={{
                  isRequired: 'A platform is required',
                  platformIsValid: 'Not a valid platform',
                }} />
}

//this is container
class AppsContainer extends Component {
  ...

  setPlatform = (platform) => {
    const { dispatch } = this.props;
    dispatch(appActions.setPlatform(platform));
    dispatch(actions.change('models.app.attributes.platform', platform));
    this.validatePlatform();
  };

  validatePlatform = () => {
    const { dispatch } = this.props;
    dispatch(actions.validate('models.app.attributes.platform', {
      platformIsValid: this.platformIsValid,
    }));
  };

  platformIsValid = (platform) => PLATFORMS.includes(platform);
  togglePlatform = (platform) => this.props.dispatch(reportsNavActions.togglePlatform(platform));

}

This seems to be working well for me:

<Control.select
  model="forms.resolution"
  component={SelectField}
  mapProps={{
    floatingLabelText: 'Resolution',
    onChange: () => handleResolutionChange,
  }}
  style={{ width: '50%' }}
>
  <MenuItem value="720p" primaryText="720p" />
  <MenuItem value="1080p" primaryText="1080p" />
  <MenuItem value="4K" primaryText="4K" />
  <MenuItem value="Custom" primaryText="Custom" />
</Control.select>

@marcandrews Nice! What happens in handleResolutionChange?

@davidkpiano In handleResolutionChange, I dispatch actions.change.

... but here's an even better way that does not require custom onChange handlers:

// Curried function that basically transforms Material-UI's onChange function
// into a react-redux-form dispatch(action.change) function.
const handleChange = ({ model, dispatch }, options = {}) =>
  (ev, index, value) =>
    dispatch(actions.change(model, value, options));

<Control.select
  model={`forms.overlay.panels[${index}].css.backgroundRepeat`}
  component={SelectField}
  mapProps={{
    floatingLabelText: 'Repeating',
    onChange: (props) => handleChange(props),
  }}
>
  <MenuItem value="repeat" primaryText="Repeat" />
  <MenuItem value="repeat-x" primaryText="Repeat horizontally" />
  <MenuItem value="repeat-y" primaryText="Repeat vertically" />
  <MenuItem value="no-repeat" primaryText="No repeating" />
</Control.select>

Was this page helpful?
0 / 5 - 0 ratings