Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Select onChange target doesn't return an html tag #8460

Closed
1 task done
robininfo-edsx opened this issue Sep 29, 2017 · 17 comments
Closed
1 task done

Select onChange target doesn't return an html tag #8460

robininfo-edsx opened this issue Sep 29, 2017 · 17 comments
Labels
support: question Community support but can be turned into an improvement

Comments

@robininfo-edsx
Copy link

robininfo-edsx commented Sep 29, 2017

  • I have searched the issues of this repository and believe that this is not a duplicate.

Expected Behavior

Get the input html tag under select

Current Behavior

Get only an object with value field

Steps to Reproduce (for bugs)

Try to render MySelect from

const setData = (e) => console.log(e.target)
export const MySelect = () => (
    <FormControl fullWidth>
        <InputLabel htmlFor="age-simple">Civilité</InputLabel>
        <Select
            value={'Monsieur'}
            onChange={setData}
            input={<Input />}
            label={'Civilité'}
            name='civility'
        >
            <MenuItem value={'Mr'}>Monsieur</MenuItem>
            <MenuItem value={'Mme'}>Madame</MenuItem>
        </Select>
    </FormControl>
)
  1. Look at your console

Context

I need to get the name field of my Select
However this one is not present in the triggered event

Your Environment

Ubuntu 17.04 (64bit)

Tech Version
Material-UI 1.0.0-beta.12
React 15.6.1
browser Chrome 61.0.3163.100 (64bit)
node 8.1.4
npm 5.4.2 
create-react-app  1.4.0 
@robininfo-edsx robininfo-edsx changed the title Select doesn't return an html tag Select changeOn target doesn't return an html tag Sep 29, 2017
@robininfo-edsx robininfo-edsx changed the title Select changeOn target doesn't return an html tag Select onChange target doesn't return an html tag Sep 29, 2017
@rosskevin
Copy link
Member

How about reproducing with the codesandbox link than was in the issue template?

@oliviertassinari
Copy link
Member

oliviertassinari commented Sep 29, 2017

@rosskevin This time, the provided information is enough to look into the issue.

I need to get the name field of my Select
However this one is not present in the triggered event

@robininfo-edsx The event is coming from a click/key interaction as you can find in:
https://github.com/callemall/material-ui/blob/6918de85cc2fc5a05ae400cc21f4d4319eae195a/src/Select/SelectInput.js#L149

You won't be able to access the hidden input field this way. This is not something we want to support. But then, I don't understand the use case as you are the one providing a name to the input.

Anyway, you can use the inputRef property on the <Input /> to get access the native hidden input field.

P.S. With the native version of the Select component, you can use the event to access the native select input field.

@oliviertassinari oliviertassinari added support: question Community support but can be turned into an improvement v1 labels Sep 29, 2017
@robininfo-edsx
Copy link
Author

robininfo-edsx commented Oct 2, 2017

I do as React documentation does because if you use something like this

const setData = (name) => (e) => console.log(e.target)
export const MySelect = () => (
    <FormControl fullWidth>
        <InputLabel htmlFor="age-simple">Civilité</InputLabel>
        <Select
            value={'Monsieur'}
            onChange={setData(civility)}
            input={<Input />}
            label={'Civilité'}
        >
            <MenuItem value={'Mr'}>Monsieur</MenuItem>
            <MenuItem value={'Mme'}>Madame</MenuItem>
        </Select>
    </FormControl>
)

You create a function each time you rerender this Component, so using a depth 1 shallow comparison will return you to rerender each time.
I know that this not really usefull as actually material-ui components are rerender each time as when you rerender a child even with same same props, the props object is never the same wich cause a rerender of each material-ui components when you rerender the parent component.
The problem is actually that onChange event took 22ms to rerender my form, so it look like less reactive to user input.

@mgrijalva
Copy link

I've been using the Formik library recently https://github.com/jaredpalmer/formik and it throws this warning:

Warning: You forgot to pass an `id` or `name` attribute to your input

Since event.target has no name or id, Formik can't figure out what input in the form changed. It works fine using <Select native> though.

Unless I'm missing something, using native selects is the only way around this?

@oliviertassinari oliviertassinari added the waiting for 👍 Waiting for upvotes label Oct 11, 2017
@oliviertassinari
Copy link
Member

@mgrijalva You are right. Formik uses the following logic. I'm curious about the integration with other form libraries. Still, you have an alternative on userland, you can write an adapter between Material-UI onChange output and Formik requirements. It's simple.

I'm adding the waiting for user feedback label. We might be able to implement something better on our side, but without more feedback, it's hard to tell. So please, people raised your voice if you encounter a similar situation.

So far we have:

  • @robininfo-edsx want to access the field name in his onChange.event.target.name.
  • @mgrijalva that has Formik constraints to deal with.

I have been looking at what Ant Design is doing with their custom select. They don't even expose the event (using rc-select internally). So the situation is worth on their end. I couldn't find any other benchmark. I think that we can keep the issue closed until further use cases is discovered.

@cvburgess
Copy link

cvburgess commented Jan 17, 2018

@oliviertassinari I am struggling through Formik issues as well. When you say:

you can write an adapter between Material-UI onChange output and Formik requirements. It's simple.

What would an adapter look like in this scenario?

@burcakulug
Copy link

burcakulug commented Jan 18, 2018

I just started playing with formik using material-ui components today. so far, it seems like you may need to write some wrapper components to integrate formik Field with MU components similar to the React Native related documentation on Formik's readme.

e.g., using render property on formik Field, you can pass a component that uses MU TextField and bind TextField.value to props.field.value and TextField.onChange to (event, newValue) => props.form.setFieldValue('someFormFieldName', newValue).

not sure if the most elegant way, but seems to be working.

@burcakulug
Copy link

oh, i saw that you can manipulate input.name via TextField.name property, so you can actually do TextField.onChange as props.form.handleChange if you set TextField.name properly. If you need to get the initial value, you also need to have TextField.value binding.

@jfperrin
Copy link

jfperrin commented Feb 7, 2018

Hi @burcakulug, have you a running example of a solution that I could use for my project ? I struggle with this warning :-(

@burcakulug
Copy link

Hi @jfperrin , I have started this personal fun project, you can take a look at this as a sample.
https://github.com/burcakulug/mytvguide/blob/master/app/containers/UsersPage/index.js#L36

For my actual work project, I implemented some wrapper components using Formik's Field and Material UI components, if that project gets opensource, I can also post it here later. For now, the one above should give you the gist.

@rullyramanda
Copy link

Hi, i'm also struggling with this warning when using Formik with the Material-ui SelectField. So i think it is enough for the devs to implement something better to resolve this issue.

@burcakulug
Copy link

i think a library wrapping mui components and bridging formik field to them would be good. that's what i sort of did for work, if i can manage, i may try to create a library for it.

@halkar
Copy link

halkar commented Mar 22, 2018

I'm having the same issue.

@cvburgess
Copy link

I wrapped this for our team - it only took a few minutes.
If no one else creates a lib for it, I wouldn't mind sharing.

@cvburgess
Copy link

cvburgess commented Mar 23, 2018

Here's an example for the TextField component:

import React from "react";
import PropTypes from "prop-types";
import { TextField } from "material-ui";

const MaterialInput = ({
  field,
  form: { touched, errors },
  label,
  ...props
}) => (
  <TextField
    {...props}
    {...field}
    value={field.value || ""}
    error={Boolean(touched[field.name] && errors[field.name])}
    label={(touched[field.name] && errors[field.name]) || label}
  />
);

MaterialInput.propTypes = {
  field: PropTypes.shape({
    name: PropTypes.string,
    value: PropTypes.any,
    onChange: PropTypes.func,
    onBlur: PropTypes.func
  }).isRequired,
  form: PropTypes.shape({
    touched: PropTypes.object,
    errors: PropTypes.object
    // the rest of the formik bag too
  }).isRequired,
  label: PropTypes.string.isRequired
};

export default MaterialInput;

Here's an example with Selects:

import React from "react";
import PropTypes from "prop-types";
import { TextField } from "material-ui";

const MaterialInputSelect = ({
  field,
  form: { touched, errors },
  label,
  options,
  ...props
}) => (
  <TextField
    {...props}
    {...field}
    value={field.value || ""}
    error={Boolean(touched[field.name] && errors[field.name])}
    label={(touched[field.name] && errors[field.name]) || label}
    select
    SelectProps={{ native: true }}
  >
    <option value="">Select</option>
    {options.map(option => (
      <option key={option.value} value={option.value}>
        {option.label}
      </option>
    ))}
  </TextField>
);

MaterialInputSelect.propTypes = {
  field: PropTypes.shape({
    name: PropTypes.string,
    value: PropTypes.any,
    onChange: PropTypes.func,
    onBlur: PropTypes.func
  }).isRequired,
  form: PropTypes.shape({
    touched: PropTypes.object,
    errors: PropTypes.object
    // the rest of the formik bag too
  }).isRequired,
  label: PropTypes.string.isRequired,
  options: PropTypes.arrayOf(
    PropTypes.shape({
      value: PropTypes.any,
      label: PropTypes.string
    })
  )
};

MaterialInputSelect.defaultProps = {
  options: []
};

export default MaterialInputSelect;

And here's an example with Switches:

import React from "react";
import PropTypes from "prop-types";
import { FormControlLabel, Switch } from "material-ui";

const MaterialInput = ({
  field: { value, ...field },
  form,
  label,
  ...props
}) => (
  <FormControlLabel
    control={<Switch {...field} {...props} checked={value || false} />}
    label={label}
  />
);

MaterialInput.propTypes = {
  field: PropTypes.shape({
    name: PropTypes.string,
    value: PropTypes.any,
    onChange: PropTypes.func,
    onBlur: PropTypes.func
  }).isRequired,
  form: PropTypes.shape({
    // the formik bag
  }).isRequired,
  label: PropTypes.string.isRequired
};

export default MaterialInput;

@greghaygood
Copy link

Chiming in late for anyone also struggling with this, since I'm using MUI with Formik as well, but wanted the non-native Select. It seems you can achieve it by passing an ID down to the visible element that matches the form field name, like so:

<TextField
  name="mySelectField"
  label="Select something ..."
  select
  required
  value={values.mySelectField}
  SelectProps={{
    SelectDisplayProps: {
      id: 'mySelectField'
    }
  }}
  onChange={handleChange}
  onBlur={handleBlur}
  >
  {mySelectOptions.map(option => (
    <MenuItem key={option.value} value={option.value}>
      {option.label}
    </MenuItem>
  ))}
</TextField>

@burcakulug
Copy link

FYI, this last snippet seems like MUI v1.x
0.x versions would similar to the previous snippets.

@oliviertassinari oliviertassinari removed the waiting for 👍 Waiting for upvotes label Nov 30, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
support: question Community support but can be turned into an improvement
Projects
None yet
Development

No branches or pull requests

10 participants