简体   繁体   中英

Toggle individual button in the form

I'm trying to implement a form with email and communication channels and want to update the form and then save it. While updating I'm facing the problem to toggle the button/icon. Please find the code below:

const [checked, setChecked] = useState(false);

  const toggleChecked = (e) => {
    setChecked((checked) => {
      return !checked;
    });
  };  




const form = useForm({
        initialValues: {
          email: "",
          communication: [
            {
              email: {
                email: "",
                notification: true,
              },
              whatsapp: {
                notification: false,
              },
            },
          ],
        },

My table content is like the below:

 <form>
            <Table>
                <thead>
                  <tr>
                    <th>Communication channel</th>
                    <th>Notifications</th>
                  </tr>
                </thead>
                <tbody>
                  <tr>
                    <td>Email</td>
                    <td>
                      
                      {checked? (
                        <CheckCircleIcon
                          className="h-6 w-6 text-green-500"
                          onClick={() => toggleChecked()}
                        />
                      ) : (
                        <XCircleIcon
                          className="h-6 w-6 text-red-500"
                          onClick={() => toggleChecked()}
                        />
                      )}
                      
                    </td>
                  </tr>
                  <tr>
                    <td>Whatsapp</td>
                    <td>
                      {checked? (
                        <CheckCircleIcon
                          className="h-6 w-6 text-green-500"
                          onClick={() => toggleChecked()}
                        />
                      ) : (
                        <XCircleIcon
                          className="h-6 w-6 text-red-500"
                          onClick={() => toggleChecked()}
                        />
                      )}
                    </td>
                  </tr>
                </tbody>
              </Table>
        </form>

What I want :

The green tick and Red cross are representing the boolean of the corresponding channel. Then should be clickable and change to the opposite symbol. In addition, user documents stored in memory should also change.

What problem I'm having now :

If I click the first icon for email the second icon for whatsapp is also changing I want to click the individual elements to change their state. What can I do? Please suggest.

use two states like: emailChecked and whatsappChecked with corresponding toggle handlers:

 const toggleEmailChecked = () => {
    setEmailChecked((checked) => {
      return !checked;
    });
  }; 

 const toggleWhatsappChecked = () => {
    setWhatsappChecked((checked) => {
      return !checked;
    });
  }; 

First of all you will need to maintain checked state of each email channel, like this

const [emailChecked, setEmailChecked] = useState(false);
const [whatsappChecked, setWhatsappChecked] = useState(false);

now you will need to have two toggle function one for email and one for whatsapp.

//for email
const toggleEmailChecked = (e) => {
setEmailChecked(!emailChecked);
};

///for whatsapp
const toggleWhatsAppChecked = (e) => {
setWhatsappChecked(!whatsappChecked);
};  

now use it like this way

<form>
        <Table>
            <thead>
              <tr>
                <th>Communication channel</th>
                <th>Notifications</th>
              </tr>
            </thead>
            <tbody>
              <tr>
                <td>Email</td>
                <td>
                  
                  {emailChecked? (
                    <CheckCircleIcon
                      className="h-6 w-6 text-green-500"
                      onClick={() => toggleEmailChecked()}
                    />
                  ) : (
                    <XCircleIcon
                      className="h-6 w-6 text-red-500"
                      onClick={() => toggleEmailChecked()}
                    />
                  )}
                  
                </td>
              </tr>
              <tr>
                <td>Whatsapp</td>
                <td>
                  {whatsappChecked? (
                    <CheckCircleIcon
                      className="h-6 w-6 text-green-500"
                      onClick={() => toggleWhatsAppChecked()}
                    />
                  ) : (
                    <XCircleIcon
                      className="h-6 w-6 text-red-500"
                      onClick={() => toggleWhatsAppChecked()}
                    />
                  )}
                </td>
              </tr>
            </tbody>
          </Table>
    </form>

hope this will help.

First solution - 2 separate states

One solution for your problem would be to keep track of two separate states, for example:

const [whatsappChecked, setWhatsappChecked] = useState(false);
const [emailChecked, setEmailChecked] = useState(false);

Then, each button would call its own setter, like this:

 <CheckCircleIcon 
   className="h-6 w-6 text-green-500" 
   onClick={() => setWhatsappChecked(!whatsappChecked)}
 />

and

<CheckCircleIcon 
   className="h-6 w-6 text-green-500" 
   onClick={() => setEmailChecked(!emailChecked)}
 />

2nd solution - extract the component and keep the state in the component

Your second solution would be to extract the state and the icons as a separate component. In that component you would keep track of whether the user toggled the individual button, the same way you do now, with just one state

const [isChecked, setIsChecked] = useState(false);

But you would call this component twice, once for each button. Each component would keep its own separate state and not be aware of the state of the other button.

The component would look something like this:

function ToggleButton() {
 const [isChecked, setIsChecked] = useState(false);

return isChecked? <CheckCircleIcon
                     className="h-6 w-6 text-green-500"
                     onClick={() => setIsChecked(!isChecked)}
                  /> 
                : <XCircleIcon
                      className="h-6 w-6 text-red-500"
                      onClick={() => setIsChecked(!isChecked)}
                   />
}

And you would call it in your form as

<tr>
  <td>Email</td>
  <td><ToggleButton /></td>
</tr>
<tr>
  <td>Whatsapp</td>
  <td><ToggleButton /></td>
</tr>

Later, if you need access to the state of each individual button, you can listen to the events on each individual component and register the effects of the clicks, or read the state of the button.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM