1

Here my question is:

How can I change the state of my default set object using multiple select ?

Here let's say, I have states checkDevice and checkCountry, so in the below fiddle I did set all values to false.

I want to set the values of only those properties to true which are selected in the multi select dropdown.

For example: In multi select, if I just select US and UK then in my state is there a way to get something like:

checkCountry: 
     {
        'US': true,
        'UK': true,
        'JP': false
      }

class Box extends React.Component {

  constructor() {
    super();
    this.state = {
      checkDevice: {
        'iPhone 4': false,
        'iPhone 5': false,
        'iPhone 6': false,
        'iPhone 7': false,
        'iPhone 8': false,
        'iPhone X': false,
      },
      checkCountry: {
        'US': false,
        'UK': false,
        'JP': false
      }
    }
  }

  componentDidMount() {
    $(document).ready(function() {
      $('#country').material_select();
    });
    $(document).ready(function() {
      $('#device').material_select();
    });
  }

  render() {
    return ( 
    <div className="card" style={{width:900,margin: 'auto'}}>
        <form className="row">
          <div className='col s6'>
            <div className="input-field">
              <select value="" multiple id="country">
                <option value="" disabled selected>Choose your option</option>
                <option value="1">US</option>
                <option value="2">UK</option>
                <option value="3">JP</option>
              </select>
              <label>Country</label>
            </div>
          </div>
          <div className='col s6'>
            <div className="input-field">
              <select value="" multiple id="device">
                <option value="" disabled selected>Choose your option</option>
                <option value="1">iPhone 4</option>
                <option value="2">iPhone 5</option>
                <option value="3">iPhone 6</option>
                <option value="4">iPhone 7</option>
                <option value="5">iPhone 8</option>
                <option value="6">iPhone X</option>
              </select>
              <label>Devices</label>
            </div>
          </div>
        </form>
        <div className="row">
        <div className="col s6">
          <pre>{JSON.stringify(this.state.checkCountry,null,2)}</pre>
        </div>
        <div className="col s6">
          <pre>{JSON.stringify(this.state.checkDevice,null,2)}</pre>
        </div>
        </div>
       </div>
    );
  };
}

ReactDOM.render( < Box / > , document.getElementById('root'));
<link href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.98.0/css/materialize.min.css" rel="stylesheet" />
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.100.2/js/materialize.min.js"></script>
<div id='root'></div>

CODEPEN, this will give you more freedom to play with.

UPDATE:

Here in the official documentation of React, we can see how to change the complete state, but is there a way to change just the property of the existing value

For Example::

handleChange(event){
    this.setState({checkCountry["event.target.value"] === true ? false: true});
} 

But I don't think, I can get in this way. But I'm trying something like this.

Ans to questions that might help: Updating an object with setstate in react

Dhaval Jardosh
  • 7,151
  • 5
  • 27
  • 69
  • Not a good idea to mix jQuery and React but if you must, you have to have an event handler to actually handle the event – Andrew Li Dec 05 '17 at 21:31
  • i tried adding an event handler https://codepen.io/swyx/pen/MOMVMY but it seems the `materialize` jquery layer is intercepting the click, the event handler is not receiving any events at all. anyone have any ideas? – swyx Dec 08 '17 at 03:57

2 Answers2

5
  1. materializecss won't trigger react onChange, so you have to bind in componentDidMount

  2. value of select is controlled by react (virtual dom remember?), so you have to assign current value to select

where I changed your code

class Box extends React.Component {
  componentDidMount() {

    //binding onchange
    $(this.countrySelect)
      .on("change", () => {
        let checkCountry = {
          US: false,
          UK: false,
          JP: false
        };
        let val = $(this.countrySelect).val();
        console.log(val);
        val.forEach(x => {
          checkCountry[x] = true;
        });
        this.setState({
          checkCountry
        });
      })
      .material_select();
  }

  render() {
    const { checkCountry } = this.state;
    const countryVal = Object.keys(checkCountry).filter(x => checkCountry[x]);
     //assigin value
    return (<select 
      ref={countrySelect => (this.countrySelect = countrySelect)}
      value={countryVal}
    />)
  }
}

see codepen https://codepen.io/postor/pen/wPLyNq?editors=1011 for result

after you know how to do it yourself. I suggest you refer this https://github.com/react-materialize/react-materialize, this might save you some time

Josh Lin
  • 2,397
  • 11
  • 21
2

You must call a event handler from a onChange event to do that.

If you weren't using a fancy jQuery plugin, you could just:

handleChange(event) {
  this.setState({name: event.target.value})
}

render(){
  
  return <input onChange={event => this.handleChange(event)}
}

But as you are using this jQuery plugin which mutates the DOM without React knowledge, you should look into the plugin API and call this event handler within the jQuery Plugin event handler.

Lets assume material_select has a onChange option. You should call your component event handler within the material_select event handler.

handleChange(event) {
      this.setState({name: event.target.value})
    }

    render(){
      
      return "Your current markup here"
    }

  componentDidMount() {
    $(document).ready(function() {
      $('#country').material_select({
        onChange: (event) => this.onChange(event)
      });
    });

  }

If you manage to do that, changing the state is just a matter of array mapping, or diffing it with a library like lodash.

By the way, you shouldn't be using jQuery with React. You should look for a React wrapper/alternative to the jQuery plugin you intend to use. This library would expose its API by props, ensuring that you could program it in the React way.

JonathanDavidArndt
  • 2,518
  • 13
  • 37
  • 49
Marco Nicolodi
  • 124
  • 1
  • 1
  • 6