Saat ini saya mencoba membuat komponen pilih/input dinamis di mana Anda dapat memilih nilai dari opsi pilih atau ketik nilai Anda sendiri di dalam bidang input dengan memilih opsi pilih "lainnya".

Saat ini saya terjebak dengan memperbarui data formulir secara merata ke nilai opsi yang dipilih/nilai input. Nilai Data Formulir selalu bertahan pada nilai awal/default.

App.js

...

export default function App() {
  const methods = useForm({});
  const { handleSubmit } = methods;

  const customSalutationOptions = [
    { title: "Not specified", value: "null" },
    { title: "Male", value: "male" },
    { title: "Female", value: "female" }
  ];

  const defaultValues = {
    salutation: "null"
  };

  const onSubmit = (data) => {
    console.log(data);
  };

  return (
    <div className="App">
      <FormProvider {...methods}>
        <form onSubmit={handleSubmit(onSubmit)}>
          <SelectOrInput
            variant="outlined"
            name={`contactPerson[0].salutation`}
            defaultValue={defaultValues}
            selectOptions={customSalutationOptions}
          />
          <Button type="submit" color="primary" fullWidth variant="contained">
            Submit
          </Button>
        </form>
      </FormProvider>
    </div>
  );
}

components/SelectOrInput.tsx

...

type Props = {
  name: string;
  label: string;
  selectOptions: [{ title: string; value: string }];
  defaultValue: any;
  shouldUnregister: boolean;
  variant: "filled" | "outlined" | "standard";
};

export default function SelectOrInput({
  name,
  label,
  selectOptions,
  defaultValue,
  shouldUnregister,
  variant
}: Props) {
  const classes = useStyles();
  const { control } = useFormContext();
  const [showCustomInput, setShowCustomInput] = useState(false);
  const [value, setValue] = useState(selectOptions[0].value);

  const additionalInput = [{ title: "Other", value: "" }];

  const combindedOptions = selectOptions.concat(additionalInput);

  const handleInputSelectChange = (
    event: React.ChangeEvent<{ value: unknown }>
  ): void => {
    const value = event.target.value as string;
    if (value === "") {
      const newState = !showCustomInput;
      setShowCustomInput(newState);
      console.log(value);
      setValue(value);
    } else {
      setValue(value);
    }
  };

  const resetCustomInputToSelect = (event: React.MouseEvent<HTMLElement>) => {
    const newState = !showCustomInput;
    setValue(combindedOptions[0].value);
    setShowCustomInput(newState);
  };

  return (
    <>
      {showCustomInput ? (
        <FormControl className={classes.input}>
          <Controller
            name={name}
            control={control}
            shouldUnregister={shouldUnregister}
            render={({ field }) => (
              <TextField
                {...field}
                label={label}
                InputLabelProps={{ shrink: true }}
                variant={variant}
                placeholder="Other..."
                autoFocus
                type="text"
                onChange={handleInputSelectChange}
                value={value}
                InputProps={{
                  endAdornment: (
                    <InputAdornment position="end">
                      <IconButton
                        size="small"
                        onClick={resetCustomInputToSelect}
                        id="custominput-closebutton"
                      >
                        <CloseIcon fontSize="small" />
                      </IconButton>
                    </InputAdornment>
                  )
                }}
              ></TextField>
            )}
          />
        </FormControl>
      ) : (
        <FormControl className={classes.input} variant={variant}>
          <InputLabel id={`label-select-${label}`}>{label}</InputLabel>
          <Controller
            name={name}
            defaultValue={defaultValue}
            control={control}
            shouldUnregister={shouldUnregister}
            render={({ field }) => (
              <Select
                {...field}
                label={label}
                labelId={`label-select-${label}`}
                value={value}
                MenuProps={{
                  anchorOrigin: {
                    vertical: "bottom",
                    horizontal: "left"
                  },
                  getContentAnchorEl: null
                }}
                onChange={handleInputSelectChange}
              >
                {combindedOptions.map((option, index) => (
                  <MenuItem key={option.title} value={`${option.value}`}>
                    {option.title}
                  </MenuItem>
                ))}
              </Select>
            )}
          />
        </FormControl>
      )}
    </>
  );
}

...

Untuk memberikan contoh yang lebih baik, saya memberikan CSB:

Edit Dynamic Input / Select

0
K.Kröger 11 Mei 2021, 13:46

2 jawaban

Jawaban Terbaik

Dengan bantuan luar biasa dari @Priyank Kachhela, saya dapat menemukan jawabannya.

Dengan Mengangkat Status ke nenek moyang terdekatnya serta menghapus Komponen Controller di dalam komponen child.

App.js

  1. Buat status di komponen induk dan inisialisasi dengan nilai default dan buat fungsi untuk mengubah nilainya
 const [inputValue, setInputValue] = useState("null");

 const onSubmit = (data) => {
    // Stringify Object to always see real value, not the value evaluated upon first expanding.
    // https://stackoverflow.com/questions/23429203/weird-behavior-with-objects-console-log
    console.log(JSON.stringify(data, 4));
  };

  const onChange = (value) => {
    setInputValue(value);
  };
  1. Bungkus SelectOrInput dengan Controller dan Teruskan onChange fungsi, value serta defaultValue ke Controller. Kemudian gunakan metode render dan sebarkan field pada Komponen SelectOrInput.

<Controller
  name={`contactPerson[0].salutation`}
  defaultValue={defaultValues.salutation}
  onChange={onChange}
  value={inputValue}
  control={control}
  render={({ field }) => (
    <SelectOrInput
     {...field}
     variant="outlined"
     selectOptions={customSalutationOptions}
     />
  )}
/>

components/SelectOrInput.js

  1. Bubble / (Call) onChange Event Handler setiap kali nilai diubah dari dalam Komponen Child-(SelectOrInput).
const handleInputSelectChange = (
    event: React.ChangeEvent<{ value: unknown }>
  ): void => {
    const value = event.target.value as string;
    if (value === "") {
      const newState = !showCustomInput;
      setShowCustomInput(newState);
      // Bubble / (Call) Event
      onChange(value);
    } else {
      onChange(value);
    }
  };

  const resetCustomInputToSelect = (event: React.MouseEvent<HTMLElement>) => {
    const newState = !showCustomInput;
    // Bubble / (Call) Event
    onChange("null");
    setShowCustomInput(newState);
  };
  1. Hapus Status Input internal komponen dari 'SelectOrInput'

Contoh Kerja

Edit Dynamic Input / Select (V.2.0)

Revisi ditangkap di dalam Gist

https://Gist.github.com/kkroeger93/1e4c0fe993f1745a34fb5717ee2ff545/revisions

0
K.Kröger 11 Mei 2021, 15:56

Anda menyimpan value dalam status komponen SelectOrInput itu sendiri. Anda perlu mengangkat status ke komponen induk untuk mendapatkan nilai di induk.

  1. Buat status di komponen induk dan inisialisasi dengan nilai default dan buat fungsi untuk mengubah nilainya
  const [inputValue, setInputValue] = useState(null);

  const onChange = (value) => {
    setInputValue(value);
  };
  1. Lewati fungsi onChange di komponen SelectOrInput dan panggil fungsi onChange setiap kali nilainya diubah
<SelectOrInput
  ...
  onChange={onChange}
/>

// call onChange in handleInputSelectChange method

  const handleInputSelectChange = (
    event: React.ChangeEvent<{ value: unknown }>
  ): void => {
    const value = event.target.value as string;
    if (value === "") {
      const newState = !showCustomInput;
      setShowCustomInput(newState);

      setValue(value);
      onChange(value);  
    } else {
      setValue(value);
      onChange(value);
    }
  };

Contoh kerja: https://codesandbox.io/s/dynamic-input-select-wk2je

1
Priyank Kachhela 11 Mei 2021, 11:22