11

I'm trying to access input data using React's "ref" attribute on a TextField in Material-UI. There doesn't seem to be an easy way of doing this via the 'inputRef' or 'inputProps'.

The below sample shows the use of inputProps on line 26. Assigning the name of the TextField to the 'ref' property does not appear to produce a valid object.

With the “inputRef”, which according the Material-ui docs forces the use of a function, attempting to pass the field data in as an attribute also doesn't work. Ex: (txt => this.name = txt)

Has anyone found a solution?

class MediaForm extends Component { constructor (props) { super(props) this.state = {} this.handleSubmit = this.handleSubmit.bind(this) } handleSubmit (e) { const { title, colour } = this.refs e.preventDefault() window.alert(`New colour: ${title.value} ${colour.value}`) } render () { const { classes } = this.props return ( <form className={classes.root} onSubmit={this.handleSubmit}> <div className={classes.field}> <TextField name='title' type='text' label='Title' placeholder='Movie title...' autoFocus inputProps={{ref: this.name}} required /> </div> <div className={classes.field}> <Tooltip title='Add a colour the reflects the mood of the film'> <TextField name='colour' type='color' label='Mood' inputProps={{ref: this.name}} required /> </Tooltip> </div> <Button variant='raised' color='primary' className={classes.button}> ADD </Button> </form> ) } } MediaForm.propTypes = { classes: PropTypes.object.isRequired } export default withRoot(withStyles(styles)(MediaForm))

2 Answers 2

7

You do not need refs for that. The submit event contains the form as the target. You can access the inputs in a form via form.elements:

handleSubmit (event) { const { title, colour } = event.currentTarget.elements; event.preventDefault(); window.alert(`New colour: ${title.value} ${colour.value}`); } 

To the problem with your refs: What does this.name refer to? You did not declare it anywhere so it is undefined. Passing undefined to the ref prop has no effect. Also how should it be possible to have two input refs being bound to the same instance property name. Are you aware that the this in your render function refers to the instance of your MediaForm component and therefore this.name is a property name on your component instance (which is undefined)?

If you want to obtain the individual refs for each input you should use the callback pattern. Note that String refs are deprecated and should not be used:

render() { return( <TextField name='title' type='text' label='Title' placeholder='Movie title...' autoFocus inputProps={{ref: input => this.titleInput = input}} required /> ); } 

EDIT:

What you probably want is known as controlled component. In this pattern your parent component keeps track of the values of it's children (often inputs):

class MediaForm extends Component { constructor(props) { super(props); this.state = { title: '', colour: '', }; } handleChange = event => { const {name, value} = event.currentTarget; this.setState({[name]: value}); }; handleSubmit = event => { event.preventDefault(); const {title, colour} = this.state; window.alert(`New colour: ${title} ${colour}`); }; render() { const {classes} = this.props; const {title, colour} = this.state; return ( <form className={classes.root} onSubmit={this.handleSubmit}> <div className={classes.field}> <TextField name="title" type="text" value={title} onChange={this.handleChange} label="Title" placeholder="Movie title..." required /> </div> <div className={classes.field}> <Tooltip title="Add a colour the reflects the mood of the film"> <TextField name="colour" type="color" value={colour} onChange={this.handleChange} label="Mood" required /> </Tooltip> </div> <Button type="submit" variant="raised" color="primary" className={classes.button} > ADD </Button> </form> ); } } 

Edit kxm42q76vv

Now your parent has full control and access over the value of each input via this.state.title and this.state.colour. Also no need for any ref here.

Sign up to request clarification or add additional context in comments.

5 Comments

You're right. My mistake. The <kbd>TextField</kbd>'s inputProps required a value, and definitely not ( this.name). I also appreciate that passing ref from input fields is not the recommended way of going about. However, the questions still remains: Is it possible to receive a value as input on a Material-UI <kbd>TextField</kbd>, assign it to ref, and then have it passed on to the submit handler to be accessed via this.refs.title and this.ref.colour?
@JohnLamy Just to understand that correctly: You basically want to have the values of the inputs accessible as variables in the parent component so that you can use them in the submit handler?
@JohnLamy You are welcome. If you feel like this solves your issue please upvote/mark it as the accepted answer.
Thank you for reminding me that I don't need to use refs or bind any events for this to work. Literally every React article about forms and events relies on refs and binding.
@JohnLamy how to use state in a form with multiple inputs, its terribly slow!
0
class MediaForm extends Component { refs = {} // <____ notice this constructor (props) { super(props) this.state = {} this.handleSubmit = this.handleSubmit.bind(this) } handleSubmit (e) { const { title, colour } = this.refs e.preventDefault() window.alert(`New colour: ${title.value} ${colour.value}`) } render () { const { classes } = this.props return ( <form className={classes.root} onSubmit={this.handleSubmit}> <div className={classes.field}> <TextField inputProps={{ref => this.refs.title = ref}} name='title' type='text' label='Title' placeholder='Movie title...' autoFocus required /> </div> <div className={classes.field}> <Tooltip title='Add a colour the reflects the mood of the film'> <TextField name='colour' inputProps={{ref => this.refs.colour = ref}} type='color' label='Mood' required /> </Tooltip> </div> <Button variant='raised' color='primary' className={classes.button}> ADD </Button> </form> ) } } MediaForm.propTypes = { classes: PropTypes.object.isRequired } export default withRoot(withStyles(styles)(MediaForm)) 

1 Comment

Looking at the your edited line 22: ref= ={ref => this.refs.title = ref}, If you meant ref={ref => this.refs.title = ref}, don't think 'refs' can be passed into TextField as its a stateless component. Not to worry. I was only curious anyway. Thanks for the prompt response.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.