Как я могу автоматически создать новую область ввода, когда пользователь начал вводить текст? - PullRequest
0 голосов
/ 29 мая 2020

Я хочу генерировать ввод динамически. Обысканы почти все образцы, и они генерируют входные данные нажатием кнопки. Это нормально, но мне нужно что-то другое. Когда пользователь начал вводить ввод, я хочу создать второй ввод, а когда пользователь вводит второй, затем создать третий ввод, как это ... входы). Я должен немедленно решить этот вопрос. Я пробовал уловки, но они не работали. Спасибо за помощь . Вы можете проверить это в Codepen.

  <div class="container1">
      <button class="add_form_field">
        Add New Field &nbsp;
        <span style="font-size: 16px; font-weight: bold;">+ </span>
      </button>
      <div class="divInput firstChild">
        <input type="text" autocomplete="off" name="mytext[]" />
      </div>
    </div>
 $(document).ready(function () {
        var max_fields = 10;
        var wrapper = $(".container1");
        var add_button = $(".add_form_field");

        var inputs = document.querySelectorAll(".divInput");
        let xs = [];
        var x = 1;
        $(add_button).click(function (e) {
          e.preventDefault();
          if (x < max_fields) {
            x++;

            $(wrapper).append(
              '<div class="divInput"><input type="text" autocomplete="off" name="mytext[]"/><a href="#" class="delete"></a></div>'
            ); //add input box
          } else {
            alert("You Reached the limits");
          }
        });



        $(wrapper).on("keyup", "input", function (e) {
          e.preventDefault();

          if ($(this).val() == "") {
            //when user cleaned input then delete it
            $(this).parent("div").remove();
            x--;
            return;
          } else if ($(this).val() != "") {
            //dont use click check if length>0 then use this trick to add new input
            $(add_button).trigger("click");
            return;
          }


          if (x == 0) {
            //if user tries to delete last input then create a new one
            console.log("xx", x);
            $(wrapper).append(
              '<div class="divInput"><input type="text" autocomplete="off" name="mytext[]"/><a href="#" class="delete"></a></div>'
            ); //add input box
            x = 1;
            console.log("xx", x);
            return;
          }
        });
      });



https://codepen.io/otontas11/pen/BaogrZR

Ответы [ 2 ]

0 голосов
/ 29 мая 2020

Я знаю, что это в основном мнение , но ИМО, вы не должны смешивать jQuery с реакцией, они используют довольно ортогональные способы sh манипуляции с пользовательским интерфейсом.

Здесь это способ, которым я выполнил этот дизайн

const createInitialState = initialValues =>
  initialValues.map(value => ({ id: uuidv4(), value })); // id used internally

const createOnChangeValues = values => values.map(({ value }) => value);

const InputList = ({ defaultValues = [], onChange }) => {
  const renderRef = useRef(null);
  const inputRef = useRef(null);
  const [values, setValues] = useState(createInitialState(defaultValues));
  const [inputFocused, setInputFocused] = useState(false);
  const [inputValue, setInputValue] = useState("");

  useEffect(() => {
    if (renderRef.current) {
      onChange && onChange(createOnChangeValues(values));
    }
    renderRef.current = true;
  }, [onChange, values]);

  const addValue = value => {
    if (value) {
      setValues(values => [...values, { id: uuidv4(), value }]);
      setInputValue("");
    }
  };

  const updateValue = index => e => {
    const updateValue = e.target.value;
    if (updateValue) {
      setValues(values =>
        values.map(({ id, value }, i) => ({
          id,
          value: index === i ? updateValue : value
        }))
      );
    } else {
      setValues(values => values.filter((_, i) => i !== index));
    }
  };

  useEffect(() => {
    if (!inputFocused && inputValue) {
      addValue(inputValue);
      inputRef.current.focus();
    }
  }, [inputFocused, inputValue]);

  const submitHandler = e => {
    e.preventDefault();
    addValue(inputValue);
  };

  const resetHandler = e => {
    e.preventDefault();
    setInputValue("");
  };

  return (
    <Fragment>
      <form id="inputForm" onReset={resetHandler} onSubmit={submitHandler} />

      {values.map(({ id, value }, i) => (
        <div key={id}>
          <input value={value} onChange={updateValue(i)} />
        </div>
      ))}

      <div>
        <input
          form="inputForm"
          ref={inputRef}
          type="text"
          value={inputValue}
          onFocus={() => setInputFocused(true)}
          onBlur={() => setInputFocused(false)}
          onChange={e => setInputValue(e.target.value)}
        />
      </div>

      {inputValue && (
        <div>
          <input />
        </div>
      )}
    </Fragment>
  );
};

Суть в том, что у вас есть некоторый массив входных данных, используемых в настоящее время, и вы всегда визуализируете дополнительный пустой ввод. Как только пользователь начинает заполнять новый пустой ввод, он становится частью массива ввода после потери фокуса. Если какой-либо ввод становится пустым, он удаляется из массива. Большая часть logi c предназначена для управления свопом с нового / пустого входа на один в массиве и сохранения фокуса.

Использование

<InputList defaultValues={[... input values from state]} onChange={... values from inputs in array} />

Edit InputList

0 голосов
/ 29 мая 2020

Во-первых, вам нужно сохранить текущий идентификатор на входе, создать событие, когда пользователь вводит и проверить идентификатор входа, и проверить, добавлен ли он уже, если нет, то продолжайте.

Вам необходимо прикрепите событие к телу , поскольку вы динамически создаете элементы.

Это то, что вы ищете?

<div id="container">
    <div class="generatedChild">
        <input type="text" childId="1" autocomplete="off" name="mytext[]"/>
    </div>
</div>
<script>
$(function(){
    var max_fields = 10;
    var wrapper = $('#container');
    // attach the event to the Body, so all generated inputs will be listened by our event
    $('body').on('input','.generatedChild input' ,function(e){
        currentId = $(this).attr("childid");
        childId = parseInt(currentId) + 1;
        childOfThisInput = $(`input[childid=${childId}]`);

        // check if is already added or if exceeds the maximum fields number
        if(currentId > max_fields || childOfThisInput.length === 1) return;

        $div = $("<div>", {class: "generatedChild"});
        $input = $('<input>', {childid: childId, autocomplete:"off", name:"mytext[]", type: "text"});
        $div.append($input);
        wrapper.append($div);

    });
});
</script>

Обновление: Если вам нужно позволить пользователю удалить некоторые из сгенерированных входных данных, вы можете попробовать что-то вроде этого:

$(function(){
    var max_fields = 10;
    var wrapper = $('#container');
    var inputsLength = 1;
    // attach the event to the Body, so all generated inputs will be listened by our event
    $('body').on('keydown','.generatedChild input' ,function(e){
        currentId = $(this).attr("childid");
        childId = parseInt(currentId) + 1;
        childOfThisInput = $(`input[childid=${childId}]`);
        if($(this).val() === "" && e.key === 8 && inputsLength > 1 )
            return remove_input($(this));
        // check if is already added or if exceeds the maximum fields number
        if(inputsLength > max_fields || childOfThisInput.length === 1 || e.key === 8) return;
            add_input(childId);
    });
    function add_input(childId){
        $div = $("<div>", {class: "generatedChild"});
        $input = $('<input>', {childid: childId, autocomplete:"off", name:"mytext[]", type: "text"});
        $div.append($input);
        wrapper.append($div);
        ++inputsLength;
    }
    function remove_input(element){
        element.parent('.generatedChild').remove();
        // let's focus the last generated input, so user won't need focus the input again
        $('.generatedChild input:last').focus();
        --inputsLength;
    }
});
...