2

I have two textboxes which has a default value of 25. I have 2 buttons; increment by 1 and decrement by 1. I do not want to manual key in the values of the textboxes, as such, I wanted to create a dropdown select to control the values of the textbox. This is how it looks like:

enter image description here

Is it possible to bind the textboxes with the select? Additional Question: Is it possible to have one [value,setValue] to control both inputs?

This is my code:

const { useState } = React;

function MyApp(){
  const [value1, setValue1]= useState(25)
  const [value2, setValue2]= useState(25)
  function increment(){
     if(selected_id == 1){ //not sure how to implement
        setValue1(value1+1)
     }
     else{
        setValue2(value2+1)
     }
  }    
  function decrement(){
     if(selected_id == 1){ //not sure how to implement
        setValue1(value1-1)
     }
     else{
        setValue2(value2-1)
     }
  }    
  return(
    <div id="react">
       <div>
         Textbox1: <input id="1" defaultValue="value1"/>
         Textbox2: <input id="2" defaultValue="value2"/>
       </div>
       <div>
          <select defaultValue="Textbox1"/>
          <button onClick={increment}> Increment </button>
          <button onClick={decrement}> Decrement </button>
       </div>
    </div>
  )
}

ReactDOM.render(
    <MyApp />,
    document.body
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.0/umd/react-dom.production.min.js"></script>

10
  • What are these Input, Select, and Button components? (Note that they're capitalized, so they aren't the input, select, and button DOM elements.) Commented Oct 31, 2020 at 9:56
  • @T.J.Crowder it's a library by antd. You were right about the second comment, it was a mistake on my end Commented Oct 31, 2020 at 9:58
  • @T.J.Crowder How can I add libraries? I usually do npm install but how do I link it here? Commented Oct 31, 2020 at 10:14
  • You click the Add an external library button, or just write a script tag, and point to a copy of the library on cdnjs.com or similar. But the only library you need for a minimal reproducible example here is React, which the page I linked to above talks about adding (it also talks about adding libs generally). (For an MRE, you would just use input, select, and button rather than wrapper components.) Commented Oct 31, 2020 at 10:23
  • @T.J.Crowder for some reason I am having some script error. are you able to help me out? Commented Oct 31, 2020 at 10:38

1 Answer 1

1

If I understand correctly, you want the select to choose which text box the Increment and Decrement buttons control. If so, then yes it's possible to do that, but no you can't have one value for both text boxes since by definition, they'll contain different values sometime.

To have the select control the buttons, you'd add a piece of state that tells the buttons what to update:

const { useState } = React;

function MyApp() {
    const [value1, setValue1] = useState(25);
    const [value2, setValue2] = useState(25);
    // The state telling us which text box to update
    const [chosenTextBox, setChosenTextBox] = useState(1);
  
    function increment(){
        // Update the relevant box
        if (chosenTextBox === 1) {
            setValue1(v => v + 1);
        } else {
            setValue2(v => v + 1);
        }
    }    
  
    function decrement(){
        if (chosenTextBox === 1) {
            setValue1(v => v - 1);
        } else {
            setValue2(v => v - 1);
        }
    }    
  
    return(
        <div id="react">
             <div>
                 Textbox1: <input id="1" value={value1} onChange={e => setValue1(+e.target.value)} />
                 Textbox2: <input id="2" value={value2} onChange={e => setValue2(+e.target.value)} />
             </div>
             <div>
                  <select value={chosenTextBox} onChange={e => setChosenTextBox(+e.target.value)}>
                      <option value="1">Textbox 1</option>
                      <option value="2">Textbox 2</option>
                  </select>
                  <button onClick={increment}> Increment </button>
                  <button onClick={decrement}> Decrement </button>
             </div>
        </div>
    )
}

ReactDOM.render(
    <MyApp />,
    document.body
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.0/umd/react-dom.production.min.js"></script>

A couple of notes on that:

  • You need to tell the text boxes what their values are. I've used value={value1} and such above.
  • Although with the code above you'd be okay using setValue1(value1 + 1) because of the specific way the state changes in that component, I recommend defaulting to using the callback style anyway. In more complex components that get their state changed in other ways, it can matter.
  • We could use arrays if there were going to be more than just a couple of text boxes

Just for the fun of it, that array approach:

const { useState } = React;

function MyApp() {
    // The values -- the length of the array dictates how many text
    // boxes there are
    const [values, setValues] = useState([25, 25, 25]);
    // The state telling us which text box to update
    const [chosenTextBox, setChosenTextBox] = useState(0);

    function modifyValue(index, delta) {
        if (index >= 0 && index < values.length) {
            setValues(values => Object.assign(
                [...values],
                {[index]: values[index] + delta}
            ));
        }
    }    
  
    function setValue(index, value) {
        if (index >= 0 && index < values.length) {
            setValues(values => Object.assign(
                [...values],
                {[index]: value}
            ));
        }
    }    
  
    return (
        <div id="react">
            <div>
                {values.map((value, index) => (
                    <div>
                        Textbox{index + 1}:
                        <input id={index + 1} value={value} onChange={e => setValue(index, +e.target.value)} />
                    </div>
                ))}
            </div>
            <div>
                 <select value={chosenTextBox} onChange={e => setChosenTextBox(+e.target.value)}>
                     {values.map((value, index) => <option value={index}>Textbox{index + 1}</option>)}
                 </select>
                 <button onClick={() => modifyValue(chosenTextBox, 1)}> Increment </button>
                 <button onClick={() => modifyValue(chosenTextBox, -1)}> Decrement </button>
            </div>
        </div>
    )
}

ReactDOM.render(
    <MyApp />,
    document.body
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.0/umd/react-dom.production.min.js"></script>

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

7 Comments

this flow of the answer (non-array approach) is correct, however, I have an issue. The state of setChosenTextBox is not updated immediately. How can I fix it?
@jason1234 - What do you mean by not "immediately"? Perhaps you're running into this common misunderstanding?
yes, it is asynchronous. If I were to switch from textbox 1 to textbox 2,my chosenTextBox value will be 1, whereas my console.log in <select value={chosenTextBox} onChange={e =>{console.log(e.target.value) setChosenTextBox(+e.target.value)}}> will return 2
@jason1234 - I'm afraid I still don't understand what you mean. When I use the live examples above, there's no problem with a delay choosing the text box. Setting state is asynchronous, but that doesn't cause any problem above. What is the actual problem you're seeing?
the value of chosenTextBox does not change when I change the select from Textbox1 to Textbox2. Thus, when I increment/decrement, it is always the previous chosenTextBox value that got incremented/decremented
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.