Reputation: 113
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))
Upvotes: 11
Views: 29875
Reputation: 16344
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>
);
}
}
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.
Upvotes: 7
Reputation: 2214
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))
Upvotes: 0