Моя кнопка отправки также отправляет другую форму

Я использую React, у меня есть форма внутри другой формы:

Когда пользователь нажимает на определенную кнопку, появляется диалоговое окно с формой, которую я хочу отправить.

Мои две формы имеют разные идентификаторы, но когда я отправляю нужную мне форму (которая находится в диалоговом окне), форма в фоновом режиме также отправляется.

Я использую react-hook-form для управления своими формами, если это тоже имеет отношение.

Я надеюсь, что это изображение может дать небольшое представление о ситуации:

Я пытался:

  • Использование разных идентификаторов для моих форм
  • Различные названия функций onSubmit
  • Размещаю кнопку onSubmit в теге <form>, который хочу отправить.
  • Установка разных уникальных идентификаторов для моих кнопок отправки.

Формы не могут быть вложены в формы, но вы можете попробовать использовать e.stopPropagation() в событии отправки вложенной формы и добавить атрибут form к кнопке отправки с идентификатором формы.

Code Spirit 30.05.2024 01:18
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
0
1
79
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

ТЛ; ДР

Используйте event.stopPropagation() вне формы React Hook handleSubmit:

<form onSubmit = {( event ) => {
  // Stop the event propagation OUTSIDE handleSubmit
  event.stopPropagation();
  // Explicitly pass the event
  handleSubmit(submitHandlerFunction)(event);
}}>
  <button type = "submit">Submit</button>
</form>

Пояснения

Форма React Hook handleSubmit запускает свой обратный вызов submitHandler после асинхронной проверки, поэтому даже если мы попытаемся использовать event.stopPropagation() внутри нашей submitHandlerFunction, уже слишком поздно предотвращать отправку «родительской» формы.

Вы можете видеть, что «родительская» форма отправляется до запуска нашего submitHandlerFunction:

function App() {
  const { handleSubmit } = useForm();

  function submitHandlerFunction(data, event) {
    event.stopPropagation(); // Attempt stopping propagation, but it is already too late...
    console.info('submitHandlerFunction called');
  }

  return (
    <form
      onSubmit = {(event) => {
        event.preventDefault();
        console.info('parent form submitted');
      }}
    >
      <h2>Parent form</h2>
      <Dialog>
        <form onSubmit = {handleSubmit(submitHandlerFunction)}>
          <h3>Child react-hook-form</h3>
          <ol>
            <li>Calls parent onSubmit</li>
            <li>Calls child submitHandlerFunction</li>
          </ol>
          <button type = "submit">Submit child form</button>
        </form>
      </Dialog>
    </form>
  );
}

Живая демонстрация: https://stackblitz.com/edit/vitejs-vite-66e51m?file=src%2FApp.jsx

Нам нужно вызвать его снаружи handleSubmit:

        <form
          onSubmit = {(event) => {
            // Stop the event propagation OUTSIDE handleSubmit
            event.stopPropagation();
            // Explicitly pass the event
            handleSubmit(submitHandlerFunction)(event);
          }}
        >
          <h3>Child react-hook-form stop propagation</h3>
          <ol>
            <li>Calls child submitHandlerFunction</li>
          </ol>
          <button type = "submit">Submit child form</button>
        </form>

Мы также можем использовать некоторую библиотеку, чтобы немного упростить, например. Browser-event-utils withStopPropagation():

Вызывает event.stopPropagation, затем передает событие предоставленной вами функции обработчика событий.

        <form
          onSubmit = {withStopPropagation(handleSubmit(submitHandlerFunction))}
        >
          <h3>Child react-hook-form withStopPropagation</h3>
          <ol>
            <li>Calls child submitHandlerFunction</li>
          </ol>
          <button type = "submit">Submit child form</button>
        </form>

Больше информации

Как упоминалось Code Spirit в комментариях к вопросу, обычно <form> не должен быть вложен в другой <form>, согласно спецификации HTML:

Обратите внимание, что вам не разрешено вкладывать элементы FORM!

См. также Можно ли вкладывать HTML-формы?

При этом, поскольку ваш «дочерний элемент» <form> появляется в модальном диалоге, он, вероятно, отображается в DOM через React Portal (например, если вы используете MUI Dialog). В этом случае он больше не вложен в «родительскую» форму, поскольку Портал «отправляет» свой HTML-контент в другую часть дерева DOM (в случае диалога MUI — как последний дочерний элемент <body>).

Хотя сейчас мы технически соответствуем спецификации HTML, к сожалению, в React это все равно не будет работать из-за поведения порталов в отношении распространения событий:

Несмотря на то, что портал может находиться в любом месте дерева DOM, во всех остальных отношениях он ведет себя как обычный дочерний элемент React. [...]

Это включает в себя всплытие событий. Событие, запущенное изнутри портала, будет распространяться на предков в содержащем его дереве React, даже если эти элементы не являются предками в дереве DOM.

Итак, мы вернулись к исходной точке: действие "submit" запускает «дочернюю» и «родительскую» формы...


Существует также возможность связать элементы формы (здесь кнопка отправки) с явной формой, как также упоминается Code Spirit в комментариях к вопросу, используя для них атрибут form="formId":

Строка, определяющая элемент <form>, с которым связаны входные данные (то есть владелец его формы). Значение этой строки, если оно присутствует, должно соответствовать id элемента <form> в том же документе. Если этот атрибут не указан, элемент <input> связан с ближайшей содержащей формой, если таковая имеется.

Атрибут form позволяет разместить ввод в любом месте документа, но включить его в форму в другом месте документа.

Но это помогает, когда эти элементы находятся за пределами своего <form> (т. е. не являются потомками в дереве DOM). Это не нарушает нормальное распространение событий.


Как уже говорилось, решение состоит в том, чтобы остановить распространение события "submit", чтобы «родительская» форма не получала его и не запускала обратный вызов onSubmit.

См. также отправить дочернюю форму, которая была внутри другой формы, и запретить отправку родительской формы, форма реагирования

Но с формой React Hook handleSubmit есть одна тонкость, см. пояснения выше.

Если вы не хотите отправлять другую форму, вы можете определить тип кнопки как кнопку для одной и отправить ее для другой.

<button type = "submit"></button>
<button type = "button"></button>

Другие вопросы по теме