Ustaw wartość przycisku opcji w Reakcie

Nov 24 2020

Tworzę prostą aplikację do reagowania z formularzem, który ma przyciski opcji.

Tutaj dostępne są domyślne dane, takie jak:

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

Wymaganie:

-> Trzeba to powtórzyć defaultDatai przypisać odpowiedni ContactModetryb jako zaznaczony w każdym wierszu.

Działający fragment:

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>

Oczekiwany wynik:

Contact Mode  Email Text Both (Checked)

Contact Mode  Email Text(Checked) Both

Contact Mode  Email Text(Checked) Both

Uwaga: nie mogę zmodyfikować atrybutu nazwy name="ContactMode". Powodem jest to, że mam również oddzielny przycisk zapisywania w każdym wierszu i po kliknięciu tego przycisku zapisywania ten konkretny wiersz zostanie zapisany .. I każdy wiersz powinien mieć name="ContactMode"...

Edytować:

Ponieważ moje pytanie nie jest jasne, co próbuję osiągnąć, podam tutaj cały kod.

-> Mam formularz steppera w którym Step 2 to sekcja zatrudnienia i domyślnie mam wartości do ustawienia w formularzu,

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

-> Inside useEffecthook ustawiam wartość formularza jak,

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

Tutaj wartości formularza z polami wejściowymi są odpowiednio powiązane, ale wartość przycisku opcji nie jest sprawdzana.

-> Dostępne są dwie dane, ale pierwsza zostanie domyślnie rozwinięta, a druga zostanie otwarta po kliknięciu Expandprzycisku poniżej pierwszej.

-> Po kliknięciu saveprzycisku ten konkretny obiekt ( inputField) zostanie zalogowany do konsoli (tylko testowanie) wraz ze zmodyfikowanymi danymi.

Tutaj PROBLEM polega na tym, że jeśli zmodyfikujemy dane, wszystko działa dobrze, ale sam atrybut sprawdzony przez radio nie powoduje sprawdzenia pozycji ... (zaznaczone wskazanie nie działa) ..

Aby zobaczyć problem, przejdź do kroku 2 w podanym poniżej polu kodów. Aby zobaczyć drugą pozycję, kliknij przycisk rozwijania.

Uprzejmie proszę o pomoc w ustawieniu domyślnej wartości przycisku opcji w każdym wierszu.

Odpowiedzi

1 DrewReese Nov 25 2020 at 14:15

W twojej piaskownicy udało mi się uruchomić przyciski radiowe

  1. Zapewnienie unikalnej namedla każdej mapowanej grupy radiowej
  2. Zaktualizuj procedurę obsługi zmian, aby unikatowo obsługiwać ContactModewłaściwość.

Zaktualizuj grupy radiowe, aby korzystały z bieżącego mapowanego indeksu, aby były unikalne wśród wszystkich mapowanych grup.

<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>

W handleInputChangedodatku przypadek do obsługi ContactModespecjalnie.

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

Myślę, że ze względu na to, że wszystkie radia mają ten sam atrybut nazwy, każda grupa powinna mieć inną nazwę. na przykład:

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

dla każdej nowej grupy należy nadać taką nazwę. jeśli zrobisz to samo imię, wszystko schrzanisz, a inni pomyślą o tobie ==zamiast===

item.ContactMode == 3

lepiej jest użyć ===

vkvkvk Nov 24 2020 at 22:49

Odpowiedź @ TalOrlanczyk jest prawidłowa. W sumie drukujesz 9 przycisków opcji i wszystkie mają tę samą wartość w atrybucie nazwy. Z technicznego punktu widzenia jest to tak, jakby mieć grupę radiową z 9 przyciskami opcji, co oznacza, że ​​grupa radiowa może przyjąć tylko jedną wartość. Uruchomiłem twój kod i zaznaczyłem tylko "Tekst" w 3. linii.

Jeśli próbujesz mieć 3 oddzielne wiersze (grupy radiowe), musisz spróbować czegoś takiego:

<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)}
/>{" "}

Wypróbuj i ponownie uruchom kod

NeetigyaChahar Nov 25 2020 at 13:16

Oto kilka problemów w Twoim kodzie ...

  1. Za każdym razem, gdy składnik powraca, .mapwywoływana jest metoda defaultData. W związku z tym nie przypisano do stanu.

  2. Jeśli chcesz mieć taką samą nazwę dla każdej iteracji, musisz użyć <form>dla każdej iteracji wszystkich innych przycisków radiowych, które zostaną zgrupowane razem, dlatego tylko ostatni przycisk opcji będzie wyświetlany jako zaznaczony.

  3. Lepiej jest używać ===zamiast==

Zmodyfikowałem twój kod i defaultDatajest używany do inicjalizacji stanu.

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>