Establecer el valor del botón de radio en React

Nov 24 2020

Estoy haciendo una aplicación de reacción simple con un formulario que tiene botones de opción.

Aquí hay datos predeterminados disponibles como,

const defaultData = [{ ContactMode: 3 }, { ContactMode: 2 }, { ContactMode: 2 }];

Requisito:

-> Necesita iterar esto defaultDatay asignar su ContactModemodo respectivo como está marcado en cada fila.

Fragmento de trabajo:

const { useState } = React;

const App = () => {
  const [formValue, setFormValue] = useState({
    ContactMode: 1
  });

  const defaultData = [{ ContactMode: 3 }, { ContactMode: 2 }, { ContactMode: 2 }];

  const handleInputChange = (e, index) => {
    const { name, value } = event.target;
    setFormValue({
      ...formValue,
      [name]: value
    });
  };

  const submitData = () => {
    console.log(formValue);
  };

  return (
    <div>
      <form>
        {defaultData.map((item, index) => {
          return (<React.Fragment>
            <label> Contact Mode </label>
            <input
              type="radio"
              name="ContactMode"
              checked={item.ContactMode == 1}
              value={1}
              onChange={(event) => handleInputChange(index, event)}
            />{" "}
            Email
            <input
              type="radio"
              name="ContactMode"
              checked={item.ContactMode == 2}
              value={2}
              onChange={(event) => handleInputChange(index, event)}
            />{" "}
            Text
            <input
              type="radio"
              name="ContactMode"
              checked={item.ContactMode == 3}
              value={3}
              onChange={(event) => handleInputChange(index, event)}
            />{" "}
            Both
            <br />
            <br />
            <button type="button">
               Save
             </button>
            <br />
            <br />
            <br />
          </React.Fragment>);
        })}
      </form>
    </div>
  );
};

ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.11.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.11.0/umd/react-dom.production.min.js"></script>
<div id="root"></div>

Rendimiento esperado:

Contact Mode  Email Text Both (Checked)

Contact Mode  Email Text(Checked) Both

Contact Mode  Email Text(Checked) Both

Nota: No puedo modificar el atributo de nombre name="ContactMode". La razón es que también tengo un botón de guardar individual en cada fila y al hacer clic en ese botón de guardar esa fila en particular se guardará .. Y cada fila debería tener name="ContactMode"..

Editar:

Como mi pregunta no es clara en lo que estoy tratando de lograr, voy a dar el código completo aquí.

-> Tengo un formulario paso a paso en el que el Paso 2 es la sección de empleo y, de forma predeterminada, tengo los valores para establecer en el formulario,

const dynamicData = [
  {
    EmploymentID: 1,
    companyName: 'Company One',
    designation: 'Designation One',
    ContactMode: 3,
  },
  {
    EmploymentID: 2,
    companyName: 'Company two',
    designation: 'Designation One',
    ContactMode: 2,
  },
];

-> Dentro del useEffectgancho configuro el valor del formulario como,

  React.useEffect(() => {
    setExpanded(0);
    setValue((prev) => {
      const companyDetails = [...dynamicData];
      return { ...prev, companyDetails };
    });
  }, []);

Aquí, los valores del formulario con cuadros de entrada están enlazados correctamente, pero el valor del botón de opción no se marca.

-> Hay dos datos disponibles, pero el primero se expandirá por defecto y mientras que el segundo se abrirá al hacer clic en el Expandbotón debajo del primero.

-> Al hacer clic en el savebotón, ese objeto en particular ( inputField) se registrará en la consola (solo pruebas) junto con los datos modificados.

Aquí el PROBLEMA es que si modificamos los datos, las cosas están funcionando bien, pero el atributo de verificación de radio por sí solo no hace que el elemento esté verificado. (La indicación de verificación no funciona).

Vaya al paso 2 en el cuadro de códigos y códigos que se proporciona a continuación para ver el problema. Para ver el segundo elemento, haga clic en el botón expandir.

Por favor, ayúdenme a establecer el valor predeterminado del botón de opción en cada fila.

Respuestas

1 DrewReese Nov 25 2020 at 14:15

En su caja de arena pude hacer que los botones de radio funcionen

  1. Proporcionar un único namepara cada grupo de radio mapeado
  2. Actualice el controlador de cambios para controlar la ContactModepropiedad de forma exclusiva .

Actualice los grupos de radio para que utilicen el índice mapeado actual para que sean únicos entre todos los grupos mapeados.

<div className="form-group col-sm-4">
  <label className="inline-flex items-center mr-6">
    <input
      type="radio"
      className="form-radio border-black"
      name={`ContactMode-${index}`} // <-- append index to name value={1} checked={inputField.ContactMode === 1} // <-- use strict "===" onChange={(event) => handleInputChange(index, event)} /> <span className="ml-2">Email</span> </label> </div> <div className="form-group col-sm-4"> <label className="inline-flex items-center mr-6"> <input type="radio" className="form-radio border-black" name={`ContactMode-${index}`}
      value={2}
      checked={inputField.ContactMode === 2}
      onChange={(event) => handleInputChange(index, event)}
    />
    <span className="ml-2">Text</span>
  </label>
</div>
<div className="form-group col-sm-4">
  <label className="inline-flex items-center mr-6">
    <input
      type="radio"
      className="form-radio border-black"
      name={`ContactMode-${index}`}
      value={3}
      checked={inputField.ContactMode === 3}
      onChange={(event) => handleInputChange(index, event)}
    />
    <span className="ml-2">Both</span>
  </label>
</div>

En el handleInputChangecaso de agregar un caso para manejar ContactModeespecialmente.

const handleInputChange = (index, event) => {
  const { name, value } = event.target;
  if (name === 'designation' && !isLettersOnly(value)) {
    return;
  }

  if (name.startsWith('ContactMode')) { // <-- check name prefix
    setValue((prev) => ({
      ...prev,
      companyDetails: prev.companyDetails.map((detail, i) =>
        i === index
          ? {
              ...detail,
              ContactMode: Number(value), // <-- store back under correct key, as number for string equality check
            }
          : detail,
      ),
    }));
    return; // <-- return early so other state update is skipped!
  }

  setValue((prev) => {
    const companyDetails = prev.companyDetails.map((v, i) => {
      if (i !== index) {
        return v;
      }

      return { ...v, [name]: value };
    });

    return { ...prev, companyDetails };
  });
};

1 TalOrlanczyk Nov 24 2020 at 22:10

Creo que debido a que todas las radios tienen el mismo atributo de nombre, cada grupo debería tener un nombre diferente. por ejemplo:

name = " ex1"
name = "ex2"
name = "ex3"

para cada nuevo grupo debido a un nombre como este. si haces el mismo nombre hace que todo se estropee otro piensa que tú en ==lugar de===

item.ContactMode == 3

es mejor usar ===

vkvkvk Nov 24 2020 at 22:49

La respuesta de @TalOrlanczyk es correcta. Está imprimiendo 9 botones de opción en total y todos tienen el mismo valor en el atributo de nombre. Entonces, técnicamente, es como tener un grupo de radio con 9 botones de radio, lo que significa que un grupo de radio solo puede aceptar un valor. Ejecuté su código y solo seleccioné "Texto" en la tercera línea.

Si está tratando de tener 3 filas separadas (grupos de radio), debe probar algo como esto:

<input
    type="radio"
    name={"ContactMode"+index}
    checked={item.ContactMode == 1}
    value={1}
    onChange={(event) => handleInputChange(index, event)}
/>{" "}
Email
<input
    type="radio"
    name={"ContactMode"+index}
    checked={item.ContactMode == 2}
    value={2}
    onChange={(event) => handleInputChange(index, event)}
/>{" "}
Text
<input
    type="radio"
    name={"ContactMode"+index}
    checked={item.ContactMode == 3}
    value={3}
    onChange={(event) => handleInputChange(index, event)}
/>{" "}

Pruébelo y vuelva a ejecutar su código

NeetigyaChahar Nov 25 2020 at 13:16

Aquí hay algunos problemas en su código ...

  1. Cada vez que el componente regresa, .mapse invoca defaultData. Por lo tanto, no se asigna al estado.

  2. Si desea el mismo nombre para cada iteración, entonces debe usar <form>para cada iteración; de lo contrario, todos los botones de opción se agruparán, por lo tanto, solo el último botón de opción se muestra como marcado.

  3. Es mejor usar en ===lugar de==

He modificado su código y defaultDatase usa para inicializar el estado.

const { useState } = React;


  const defaultData = [{ ContactMode: 3 }, { ContactMode: 2 }, { ContactMode: 2 }];

const App = () => {

  const [formValue, setFormValue] = useState([...defaultData]);

  const handleInputChange = (index, e) => {
    const { name, value } = e.target;

    const newFormValue = [...formValue];
    newFormValue.splice(index,1,{[name]: value});
    
    setFormValue(newFormValue);
  };

  const submitData = () => {
    console.log(formValue);
  };

  return (
    <div>
        {formValue.map((item, index) => {
          return (<form>
            <label> Contact Mode </label>
            <input
              type="radio"
              name="ContactMode"
              checked={Number(item.ContactMode) === 1}
              value={1}
              onChange={(event) => handleInputChange(index, event)}
            />{" "}
            Email
            <input
              type="radio"
              name="ContactMode"
              checked={Number(item.ContactMode) === 2}
              value={2}
              onChange={(event) => handleInputChange(index, event)}
            />{" "}
            Text
            <input
              type="radio"
              name="ContactMode"
              checked={Number(item.ContactMode) === 3}
              value={3}
              onChange={(event) => handleInputChange(index, event)}
            />{" "}
            Both
            <br />
            <br />
          </form>);
        })}
        <button type="button" onClick={submitData}>
          {" "}
          Submit{" "}
        </button>
    </div>
  );
};

ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.11.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.11.0/umd/react-dom.production.min.js"></script>
<div id="root"></div>