Асинхронная отправка формы

Отправляем данные формы без перезагрузки страницы.

Время чтения: меньше 5 мин

Задача

Скопировано

Возможно, вы хотите иметь больше контроля над вашей формой: показывать лоадер при отправке данных или обновить интерфейс ещё до получения ответа сервера. Если у формы есть атрибут method со значением get или post, то при отправке формы страница перезагрузится. Разберёмся, как отключить это дефолтное поведение и взять все в свои руки.

Готовое решение

Скопировано
        
          
          <form>  <label>    Почта:    <input type="email" autocomplete="email" name="email" required>  </label>  <label>    Пароль:    <input type="password" name="password" autocomplete="current-password" required>  </label>  <button type="submit">Войти</button></form>
          <form>
  <label>
    Почта:
    <input type="email" autocomplete="email" name="email" required>
  </label>
  <label>
    Пароль:
    <input type="password" name="password" autocomplete="current-password" required>
  </label>
  <button type="submit">Войти</button>
</form>

        
        
          
        
      
        
          
          const form = document.querySelector("form")const submitButton = document.querySelector("button")if (form) {  form.addEventListener("submit", handleFormSubmit)}async function handleFormSubmit(event) {  // Отключаем дефолтное поведение  event.preventDefault()  disableButton()  try {    showLoader()    const response = await fetch("/api/login", {      method: "POST",      body: new FormData(form)    })    const result = await response.json()  } catch (error) {    showError(error)  } finally {    hideLoader()    enableButton()  }}function disableButton() {  if (submitButton) submitButton.disabled = true}function enableButton() {  if (submitButton) submitButton.disabled = false}function showLoader() {  // Показываем пользователю лоадер}function hideLoader() {  // Скрываем лоадер от пользователя}function showError() {  // Показываем пользователю ошибку}
          const form = document.querySelector("form")
const submitButton = document.querySelector("button")

if (form) {
  form.addEventListener("submit", handleFormSubmit)
}

async function handleFormSubmit(event) {
  // Отключаем дефолтное поведение
  event.preventDefault()
  disableButton()

  try {
    showLoader()
    const response = await fetch("/api/login", {
      method: "POST",
      body: new FormData(form)
    })
    const result = await response.json()
  } catch (error) {
    showError(error)
  } finally {
    hideLoader()
    enableButton()
  }
}

function disableButton() {
  if (submitButton) submitButton.disabled = true
}

function enableButton() {
  if (submitButton) submitButton.disabled = false
}

function showLoader() {
  // Показываем пользователю лоадер
}

function hideLoader() {
  // Скрываем лоадер от пользователя
}

function showError() {
  // Показываем пользователю ошибку
}

        
        
          
        
      

Разбор решения

Скопировано

Напишем простую формочку с двумя полями: почтой и паролем.

        
          
          <form>  <label>    Почта:    <input type="email" autocomplete="email" name="email" required>  </label>  <label>    Пароль:    <input type="password" name="password" autocomplete="current-password" required>  </label>  <button type="submit">Войти</button></form>
          <form>
  <label>
    Почта:
    <input type="email" autocomplete="email" name="email" required>
  </label>
  <label>
    Пароль:
    <input type="password" name="password" autocomplete="current-password" required>
  </label>
  <button type="submit">Войти</button>
</form>

        
        
          
        
      

Найдём нашу форму по тегу <form>.

        
          
          const form = document.querySelector("form")
          const form = document.querySelector("form")

        
        
          
        
      

На форму добавим обработчик события submit и отключим дефолтное поведение события с помощью метода preventDefault().

        
          
          if (form) {  form.addEventListener("submit", handleFormSubmit)}async function handleFormSubmit(event) {  event.preventDefault()}
          if (form) {
  form.addEventListener("submit", handleFormSubmit)
}

async function handleFormSubmit(event) {
  event.preventDefault()
}

        
        
          
        
      

Теперь наша страница не будет перезагружаться, а мы можем, например, не только отправить запрос, но и показать пользователю лоадер или ошибку.

        
          
          async function handleFormSubmit(event) {  // Отключаем дефолтное поведение  event.preventDefault()  try {    showLoader()    const response = await fetch("/api/login", {      method: "POST",      body: new FormData(form)    })    const result = await response.json()  } catch (error) {    showError(error)  } finally {    hideLoader()  }}function showLoader() {  // Показываем пользователю лоадер}function hideLoader() {  // Скрываем лоадер от пользователя}function showError() {  // Показываем пользователю ошибку}
          async function handleFormSubmit(event) {
  // Отключаем дефолтное поведение
  event.preventDefault()

  try {
    showLoader()
    const response = await fetch("/api/login", {
      method: "POST",
      body: new FormData(form)
    })
    const result = await response.json()
  } catch (error) {
    showError(error)
  } finally {
    hideLoader()
  }
}

function showLoader() {
  // Показываем пользователю лоадер
}

function hideLoader() {
  // Скрываем лоадер от пользователя
}

function showError() {
  // Показываем пользователю ошибку
}

        
        
          
        
      

Также можно отключить кнопку, пока сервер не пришёл с ответом, чтобы предотвратить повторную отправку формы.

        
          
          async function handleFormSubmit(event) {  // Отключаем дефолтное поведение  event.preventDefault()  disableButton()  try {    showLoader();    const response = await fetch("/api/login", {      method: "POST",      body: new FormData(form)    })    const result = await response.json()  } catch (error) {    showError(error)  } finally {    hideLoader()    enableButton()  }}function disableButton() {  if (submitButton) submitButton.disabled = true}function enableButton() {  if (submitButton) submitButton.disabled = false}
          async function handleFormSubmit(event) {
  // Отключаем дефолтное поведение
  event.preventDefault()
  disableButton()

  try {
    showLoader();
    const response = await fetch("/api/login", {
      method: "POST",
      body: new FormData(form)
    })
    const result = await response.json()
  } catch (error) {
    showError(error)
  } finally {
    hideLoader()
    enableButton()
  }
}

function disableButton() {
  if (submitButton) submitButton.disabled = true
}

function enableButton() {
  if (submitButton) submitButton.disabled = false
}