How get data from material-ui TextField, DropDownMenu components?

162,551

Solution 1

Add an onChange handler to each of your TextField and DropDownMenu elements. When it is called, save the new value of these inputs in the state of your Content component. In render, retrieve these values from state and pass them as the value prop. See Controlled Components.

var Content = React.createClass({

    getInitialState: function() {
        return {
            textFieldValue: ''
        };
    },

    _handleTextFieldChange: function(e) {
        this.setState({
            textFieldValue: e.target.value
        });
    },

    render: function() {
        return (
            <div>
                <TextField value={this.state.textFieldValue} onChange={this._handleTextFieldChange} />
            </div>
        )
    }

});

Now all you have to do in your _handleClick method is retrieve the values of all your inputs from this.state and send them to the server.

You can also use the React.addons.LinkedStateMixin to make this process easier. See Two-Way Binding Helpers. The previous code becomes:

var Content = React.createClass({

    mixins: [React.addons.LinkedStateMixin],

    getInitialState: function() {
        return {
            textFieldValue: ''
        };
    },

    render: function() {
        return (
            <div>
                <TextField valueLink={this.linkState('textFieldValue')} />
            </div>
        )
    }

});

Solution 2

use the accepted answer / this was the answer to another (already deleted) question

@karopastal

add a ref attribute to your <TextField /> component and call getValue() on it, like this:

Component:

<TextField ref="myField" />

Using getValue:

this.refs.myField.getValue()

Solution 3

Here all solutions are based on Class Component, but i guess most of the people who learned React recently (like me), at this time using functional Component. So here is the solution based on functional component.

Using useRef hooks of ReactJs and inputRef property of TextField.

    import React, { useRef, Component } from 'react'
    import { TextField, Button } from '@material-ui/core'
    import SendIcon from '@material-ui/icons/Send'

    export default function MultilineTextFields() {
    const valueRef = useRef('') //creating a refernce for TextField Component

    const sendValue = () => {
        return console.log(valueRef.current.value) //on clicking button accesing current value of TextField and outputing it to console 
    }

    return (
        <form noValidate autoComplete='off'>
        <div>
            <TextField
            id='outlined-textarea'
            label='Content'
            placeholder='Write your thoughts'
            multiline
            variant='outlined'
            rows={20}
            inputRef={valueRef}   //connecting inputRef property of TextField to the valueRef
            />
            <Button
            variant='contained'
            color='primary'
            size='small'
            endIcon={<SendIcon />}
            onClick={sendValue}
            >
            Send
            </Button>
        </div>
        </form>
    )
    }

Solution 4

Try this,

import React from 'react';
import {useState} from 'react';

import TextField from '@material-ui/core/TextField';

const Input = () => {
    const [textInput, setTextInput] = useState('');

    const handleTextInputChange = event => {
        setTextInput(event.target.value);
    };
    
    return(
        <TextField
            label="Text Input"
            value= {textInput}
            onChange= {handleTextInputChange}
        />
    );
}

export default Input;

Explanation if the above code was not clear.

First we create a state to store the text input called textInput and assign it the value ''.

Then we return a material UI <TextField /> component whose value attribute is set to the textInput state. Doing this we display the current value of the textInput in the <TextField />. Any changes to the value of textInput will change the value attribute of the <TextField />, courtesy of React.

Then we use the onChange attribute of <TextField /> to run a handler function every time the value of the <TextField /> value attribute changes. This handler function is an arrow function stored in the constant handleTextInputChange. It takes an event as an argument. When the onChange attribute runs the handler function, it sends the event as an argument to the handler function.

The value of the <TextField /> is stored in event.target.value. We then use the setTextInput method of the state to set the state to the value attribute of the <TextField />. Thus this change is reflected in the <TextField /> whose value attribute is the value of the textInput state.

Thus the data input into the <TextField /> is stored in the state textInput, ready to be used when required.

Solution 5

The strategy of the accepted answer is correct, but here's a generalized example that works with the current version of React and Material-UI.

The flow of data should be one-way:

  • the initialState is initialized in the constructor of the MyForm control
  • the TextAreas are populated from this initial state
  • changes to the TextAreas are propagated to the state via the handleChange callback.
  • the state is accessed from the onClick callback---right now it just writes to the console. If you want to add validation it could go there.
import * as React from "react";
import TextField from "material-ui/TextField";
import RaisedButton from "material-ui/RaisedButton";

const initialState = {
    error: null, // you could put error messages here if you wanted
    person: {
        firstname: "",
        lastname: ""
    }
};

export class MyForm extends React.Component {

    constructor(props) {
        super(props);
        this.state = initialState;
        // make sure the "this" variable keeps its scope
        this.handleChange = this.handleChange.bind(this);
        this.onClick = this.onClick.bind(this);
    }

    render() {
        return (
            <div>
                <div>{this.state.error}</div>
                <div>
                    <TextField
                        name="firstname"
                        value={this.state.person.firstname}
                        floatingLabelText="First Name"
                        onChange={this.handleChange}/>
                    <TextField
                        name="lastname"
                        value={this.state.person.lastname}
                        floatingLabelText="Last Name"
                        onChange={this.handleChange}/>
                </div>
                <div>
                    <RaisedButton onClick={this.onClick} label="Submit!" />
                </div>
            </div>
        );
    }

    onClick() {
        console.log("when clicking, the form data is:");
        console.log(this.state.person);
    }

    handleChange(event, newValue): void {
        event.persist(); // allow native event access (see: https://facebook.github.io/react/docs/events.html)
        // give react a function to set the state asynchronously.
        // here it's using the "name" value set on the TextField
        // to set state.person.[firstname|lastname].            
        this.setState((state) => state.person[event.target.name] = newValue);

    }

}


React.render(<MyForm />, document.getElementById('app'));

(Note: You may want to write one handleChange callback per MUI Component to eliminate that ugly event.persist() call.)

Share:
162,551
Vitalii Trachenko
Author by

Vitalii Trachenko

Updated on July 08, 2022

Comments

  • Vitalii Trachenko
    Vitalii Trachenko almost 2 years

    I create form, I have several TextField, DropDownMenu material-ui components included, question is how I can collect all data from all TextFields, DropDownMenus in one obj and sent it on server. For TextField it has TextField.getValue() Returns the value of the input. But I can`t understand how to use it.

    var React = require('react'),
        mui = require('material-ui'),
        Paper = mui.Paper,
        Toolbar = mui.Toolbar,
        ToolbarGroup = mui.ToolbarGroup,
        DropDownMenu = mui.DropDownMenu,
        TextField = mui.TextField,
        FlatButton = mui.FlatButton,
        Snackbar = mui.Snackbar;
    
    var menuItemsIwant = [
      { payload: '1', text: '[Select a finacial purpose]' },
      { payload: '2', text: 'Every Night' },
      { payload: '3', text: 'Weeknights' },
      { payload: '4', text: 'Weekends' },
      { payload: '5', text: 'Weekly' }
    ];
    var menuItemsIcan = [
      { payload: '1', text: '[Select an objective]' },
      { payload: '2', text: 'Every Night' },
      { payload: '3', text: 'Weeknights' },
      { payload: '4', text: 'Weekends' },
      { payload: '5', text: 'Weekly' }
    ];
    var menuItemsHousing = [
      { payload: '1', text: '[Select housing]' },
      { payload: '2', text: 'Every Night' },
      { payload: '3', text: 'Weeknights' },
      { payload: '4', text: 'Weekends' },
      { payload: '5', text: 'Weekly' }
    ];
    var menuItemsIlive = [
      { payload: '1', text: '[Select family mambers]' },
      { payload: '2', text: 'Every Night' },
      { payload: '3', text: 'Weeknights' },
      { payload: '4', text: 'Weekends' },
      { payload: '5', text: 'Weekly' }
    ];
    var menuItemsLifestyle = [
      { payload: '1', text: '[Select lifestyle]' },
      { payload: '2', text: 'Every Night' },
      { payload: '3', text: 'Weeknights' },
      { payload: '4', text: 'Weekends' },
      { payload: '5', text: 'Weekly' }
    ];
    var menuItemsLifestyle2 = [
      { payload: '1', text: '[Select savings]' },
      { payload: '2', text: 'Every Night' },
      { payload: '3', text: 'Weeknights' },
      { payload: '4', text: 'Weekends' },
      { payload: '5', text: 'Weekly' }
    ];
    var menuItemsIncome = [
      { payload: '1', text: '[Select your yearly income]' },
      { payload: '2', text: 'Every Night' },
      { payload: '3', text: 'Weeknights' },
      { payload: '4', text: 'Weekends' },
      { payload: '5', text: 'Weekly' }
    ];
    var Content = React.createClass({
    
      getInitialState: function() {
        return {
          //formData: {
          //  name: '',
          //  age: '',
          //  city: '',
          //  state: ''
          //},
          errorTextName: '',
          errorTextAge: '',
          errorTextCity: '',
          errorTextState: ''
        };
      },
    
      render: function() {
    
        return (
          <div className="container-fluid">
            <div className="row color-bg"></div>
            <div className="row main-bg">
              <div className="container">
                <div className="mui-app-content-canvas page-with-nav">
                  <div className="page-with-nav-content">
    
                    <Paper zDepth={1}>
    
                      <h2 className="title-h2">Now, what would you like to do?</h2>
    
                      <Toolbar>
                        <ToolbarGroup key={1} float="right">
                          <span>I want to</span>
                          <DropDownMenu
                            className="dropdown-long"
                            menuItems={menuItemsIwant}
                            //autoWidth={false}
                          />
                        </ToolbarGroup>
                      </Toolbar>
    
                      <div className="clearfix"></div>
    
                      <Toolbar>
                        <ToolbarGroup key={2} float="right">
                          <span>So I can</span>
                          <DropDownMenu
                            className="dropdown-long"
                            menuItems={menuItemsIcan}
                            //autoWidth={false}
                          />
                        </ToolbarGroup>
                      </Toolbar>
    
                      <h2 className="title-h2">Please, share a little about you.</h2>
    
                      <div className="clearfix"></div>
    
                      <Toolbar>
                        <ToolbarGroup key={3} float="right">
                          <span>I am</span>
                          <TextField
                            id="name"
                            className="text-field-long"
                            ref="textfield"
                            hintText="Full name"
                            errorText={this.state.errorTextName}
                            onChange={this._handleErrorInputChange}
                          />
                          <span>and I am</span>
                          <TextField
                            id="age"
                            className="text-field-short"
                            ref="textfield"
                            hintText="00"
                            errorText={this.state.errorTextAge}
                            onChange={this._handleErrorInputChange}
                          />
                          <span className="span-right-measure">years of age.</span>
                        </ToolbarGroup>
                      </Toolbar>
    
                      <div className="clearfix"></div>
    
                      <Toolbar>
                        <ToolbarGroup key={4} float="right">
                          <span>I</span>
                          <DropDownMenu
                            hintText="I"
                            menuItems={menuItemsHousing}
                            //autoWidth={false}
                          />
                          <span>in</span>
                          <TextField
                            id="city"
                            ref="textfield"
                            className="text-field-long"
                            hintText="City"
                            errorText={this.state.errorTextCity}
                            onChange={this._handleErrorInputChange}
                          />
                          <span>,</span>
                          <TextField
                            id="state"
                            ref="textfield"
                            className="text-field-short text-field-right-measure"
                            hintText="ST"
                            errorText={this.state.errorTextState}
                            onChange={this._handleErrorInputChange}
                          />
                        </ToolbarGroup>
                      </Toolbar>
    
                      <div className="clearfix"></div>
    
                      <Toolbar>
                        <ToolbarGroup key={5} float="right">
                          <span>Where I live</span>
                          <DropDownMenu
                            className="dropdown-long"
                            menuItems={menuItemsIlive}
                            //autoWidth={false}
                          />
                        </ToolbarGroup>
                      </Toolbar>
    
                      <div className="clearfix"></div>
    
                      <Toolbar>
                        <ToolbarGroup key={6} float="right">
                          <span>My lifestyle is</span>
                          <DropDownMenu
                            className="dropdown-short"
                            menuItems={menuItemsLifestyle}
                            //autoWidth={false}
                          />
                          <span>and I've saved</span>
                          <DropDownMenu
                            className="dropdown-short"
                            menuItems={menuItemsLifestyle2}
                            //autoWidth={false}
                          />
                        </ToolbarGroup>
                      </Toolbar>
    
                      <div className="clearfix"></div>
    
                      <Toolbar>
                        <ToolbarGroup key={7} float="right">
                          <span>My yearly household is about</span>
                          <DropDownMenu
                            className="dropdown-mobile"
                            menuItems={menuItemsIncome}
                            //autoWidth={false}
                          />
                        </ToolbarGroup>
                      </Toolbar>
    
                      <div className="clearfix"></div>
    
                      <div className="button-place">
                        <FlatButton
                          onTouchTap={this._handleClick}
                          label="I'm done lets go!"
                        />
    
                        <Snackbar
                          ref="snackbar"
                          message="Invalid input, please check and try again"
                        />
                      </div>
    
                    </Paper>
    
                  </div>
                </div>
              </div>
            </div>
          </div>
        );
      },
    
      _handleErrorInputChange: function(e) {
        if (e.target.id === 'name') {
          var name = e.target.value;
          this.setState({
            //name: name,
            errorTextName: e.target.value ? '' : 'Please, type your Name'
          });
        } else if (e.target.id === 'age') {
          var age = e.target.value;
          this.setState({
            //age: age,
            errorTextAge: e.target.value ? '' : 'Check Age'
          });
        } else if (e.target.id === 'city') {
          var city = e.target.value;
          this.setState({
            //city: city,
            errorTextCity: e.target.value ? '' : 'Type City'
          });
        } else if (e.target.id === 'state') {
          var state = e.target.value;
          this.setState({
            //state: state,
            errorTextState: e.target.value ? '' : 'Type State'
          });
        }
      },
    
      _handleClick: function(e) {
        this.refs.snackbar.show();
        //TODO: find a way to change errorText for all empty TextField
        if (this.refs.textfield && this.refs.textfield.getValue().length === 0) {
          this.setState({
            errorTextState: 'Type State',
            errorTextCity: 'Type City',
            errorTextAge: 'Check Age',
            errorTextName: 'Please, type your Name'
          });
        }
      }
    
    });
    
    module.exports = Content;
    

    I want sent it on server in _handleClick method.

  • can.
    can. almost 9 years
    This method is better
  • rosnk
    rosnk over 8 years
    this seems to be the proper way to use material-UI documentation. Was doing "this.refs.myField.getDOMNode.getValue()" but was doing completely wrong, thanks for the answer.
  • rosnk
    rosnk over 8 years
    @flson it does not work with dropdown, how do you do for dropdown. Works with rest of the component though. Have opened another question, if you have answer please help me out. link: stackoverflow.com/questions/32633272/…
  • thetrystero
    thetrystero over 8 years
    isn't is bad to use refs? stackoverflow.com/questions/29503213/…
  • thetrystero
    thetrystero over 8 years
    using this method, setState is always one step behind. i had to revert to using value and onChange.
  • Mido
    Mido over 8 years
    It is worth noting that the onChange handler for the DropDownMenu component will get called with the following arguments: event, key, payload. Payload is the selected MenuItem's value. Key is the MenuItem's index. See the source: github.com/callemall/material-ui/blob/master/src/DropDownMen‌​u/…
  • sebastienbarbier
    sebastienbarbier over 7 years
    Quoting react documentation : ReactLink is deprecated as of React v15. The recommendation is to explicitly set the value and change handler, instead of using ReactLink. facebook.github.io/react/docs/two-way-binding-helpers.html
  • rkstar
    rkstar over 7 years
    using this.refs has been/ is being deprecated in favour of using controlled components. do not use this.
  • d4nyll
    d4nyll about 7 years
    There are situations where using refs are better - stackoverflow.com/a/34622774/3966682 - always using controlled components can be extremely inefficient, especially if you have heavily-nested components, where you'll have to pass the same onChange function down 5-6 times, on every keystroke. Use what best fits the situation.
  • Adam
    Adam about 7 years
    What is this, where should they put it? What does it do? This answer isn't helpful without additional context?
  • Eesa
    Eesa over 6 years
    I think this method has been deprecated.
  • Dennis
    Dennis about 6 years
    why the underscore in _handleTextFieldChange?
  • Alexandre Kirszenberg
    Alexandre Kirszenberg about 6 years
    @Mr.White Just a stylistic convention, as we'd consider that method to be private, i.e. it would not make sense to call it from outside of that component's context. I do not personally enforce this convention, I just reused the code sample from Vitalii's question.
  • aye2m
    aye2m almost 6 years
    I get runtime error: Stateless function components cannot have refs.
  • dush88c
    dush88c almost 6 years
    When a user is typing characters one by one, onChange event is fired and call setState to update value, Then render is called, again and again, So when typing user feels slowness and stuck of typing. how to avoid this sort of situation?
  • tommybernaciak
    tommybernaciak over 5 years
    you can no longer use this method anymore
  • DSLuminary
    DSLuminary over 4 years
    This is an example of an uncontrolled component, which is fine, but not recommended according to the docs.
  • HirdayGupta
    HirdayGupta about 4 years
    I think this needs to be the accepted answer in 2020
  • Harsh Phoujdar
    Harsh Phoujdar almost 4 years
    Property 'value' does not exist on type 'string'.
  • yainspan
    yainspan over 3 years
    You don't need to import Component from React if you're using functional components.
  • Semih Arslanoglu
    Semih Arslanoglu almost 3 years
    Can you add an explanation to your solution?
  • Manil Malla
    Manil Malla almost 3 years
    @SemihArslanoğlu I have added an explanation to my solution. I hope you find it comprehensible.
  • Adarsh Raj
    Adarsh Raj almost 2 years
    This slow down on Phone like Samsung A30 or same hardware.