FormData - Объект JavaScript для кодирования данных формы

Содержание:
  1. Назначение объекта FormData
  2. Структура объекта FormData
  3. Работа с объектом FormData
  4. Использование FormData для кодирования данных формы
  5. Использование FormData для отправки файлов на сервер
  6. Комментарии

Статья, в которой познакомимся с методом FormData и научимся его использовать для кодирования данных, которые необходимо отправить на сервер посредством технологии AJAX в формате "multipart/form-data".

Назначение объекта FormData

Объект FormData предназначен для кодирования данных, которые необходимо отправить на сервер посредством технологии AJAX (XMLHttpRequest).

Для кодирования данных метод FormData использует формат "multipart/form-data". Это означает то, что он позволяет подготовить для отправки по AJAX не только текстовые данные, но и файлы (input с type, равным file).

Передачу на сервер данных, находящихся в объекте FormData, необходимо осуществлять посредством метода POST.

Структура объекта FormData

Представить себе объект FormData можно как набор пар "ключ-значение". Другими словами, как некоторую коллекцию элементов в которой каждый из них представлен в виде ключа и значения (массива значений).

Структура объекта FormData
Структура объекта FormData

Работа с объектом FormData

Работа с объектом FormData начинается с его создания:

// создание объекта FormData
var formData = new FormData();

При создании объекта FormData ему можно в качестве параметра указать DOM форму. В этом случае в объект FormData автоматически добавятся все поля (имяПоля:значение) этой формы.

// создание объекта FormData и добавлением в него всех полей формы subscribe
var formData = new FormData(document.forms.subscribe);

После создания объекта FormData вы можете использовать его различные методы.

Один из наиболее используемых методов – это append (поддерживается большинством браузеров). Этот метод добавляет в объект FormData новую порцию данных (ключ-значение). При этом если указанного ключа нет в объекте, то данный метод добавит в FormData новый элемент ("ключ-значение").

formData.append('key','value1'); //"key":"value1"

В противном случае если указанный ключ есть уже у объекта FormData, то данный метод запишет его значение в качестве следующего значения этого ключа. После этого, с указанным ключом уже будет связано несколько значений (массив значений).

formData.append('key','value2'); //"key":["value1", "value2"]

Другой метод для добавления данных в объект FormData – это set (поддерживается не всеми браузерами). Отличается данный метод от append только тем, что он не добавляет ещё одно значение для ключа (если оно уже есть). Он просто изменяет текущее значение.

formData.set('key','value3'); //"key":"value3"

Для удаления данных из объекта FormData предназначен метод delete. Он убирает элемент из объекта FormData по имени ключа.

formData.delete('key');

Метод has позволяет поверить в объекте FormData наличия указанного ключа.

// данный метод вернёт true, если в FormData есть элемент с ключом key
// в противном случае он вернёт значение false
formData.delete('key');

Если вам необходимо узнать значение, связанное с ключом, то можно воспользоваться методом get. Если с ключом связано несколько значений, то данный метод вернёт первое из набора. Кроме метода get, есть ещё метод getAll. Он позволяет получить массив значений, связанных с указанным ключом.

// возвращает первое значение связанное с ключом key
formData.get('key'); // например: "value1"
// получить массив значений связанных с ключом
formData.getAll('key'); // например: ["value1","value2"]

Использование FormData для кодирования данных формы

Рассмотрим простой AJAX пример, в котором разберём, как применять объект FormData для кодирования данных формы.

Данный пример будет выполнять следующие основные действия:

  • отправлять HTML форму на сервер методом POST (подготавливать данные для отправки запроса будем осуществлять с помощью объекта FormData);
  • обрабатывать данные формы на сервере посредством php и формировать на основании них ответ в формате json;
  • получать ответ от сервера и выводить его после некоторой обработки посредством JavaScript на страницу.

Разработку этого примера начнём с создания HTML формы и контейнера для вывода результата.

<div class="container">
  <div class="panel panel-danger">
    <div class="panel-heading">Данные, которые пришли с сервера:</div>
    <!-- Контейнер для вывода результата (id = "result") -->
    <div class="panel-body" id="result"></div>
  </div>
  <!-- HTML форма, данные которой будем отправлять на сервер по технологии AJAX (id="message") -->
  <form id="message">
    <div class="form-group">
      <label for="name">Имя:</label>
      <input type="text" class="form-control" name="name">
    </div>
    <div class="form-group">
      <label for="name">Сообщение:</label>
      <textarea class="form-control" rows="3" name="message"></textarea>
    </div>
    <button id="send-message" class="btn btn-primary">Отправить сообщение</button>
  </form>
</div>

PHP сценарий, который будет формировать ответ клиенту в формате JSON. Для создания ответа будем использовать ключи name и message суперглобального массива POST.

<?php
  // если в массиве $_POST есть ключ name и его значение не равно пустоте, то
  if ((isset($_POST['name'])) && (!empty($_POST["name"]))) {
    // присвоить $result['name'] значение $_POST['name']
    $result['name'] = $_POST['name'];
  } else {
    // иначе, $result['name'] присвоить указанную строку
    $result['name'] = 'Вы не ввели поле name!';
  }
  // если в массиве $_POST есть ключ message и его значение не равно пустоте, то
  if ((isset($_POST['message']))&& (!empty($_POST["message"]))) {
    // присвоить $result['message'] значение $_POST['message']
    $result['message'] = $_POST['message'];
  } else {
    // иначе, $result['message'] присвоить указанную строку
    $result['message'] = 'Вы не ввели поле message!';
  }
  // преобразовать массив $result в json, а затем вывести его с помощью echo
  echo json_encode($result);
?>

Сценарий на JavaScript, который будет кодировать данные HTML формы (FormData), отправлять её на сервер (XMLHttpRequest), получать ответ с сервера и отображать его на странице в виде маркированного списка.

<script>
// после загрузки DOM модели
document.addEventListener('DOMContentLoaded', function() {
  // получим форму с id = "message"
  var message = document.getElementById('message');
  // при возникновении у формы события submit
  message.addEventListener('submit', function(e) {
    // создадим объект FormData и добавим в него данные из формы
    var formData = new FormData(message);
    // создадим объект XHR
    var request = new XMLHttpRequest();
    // инициализирум запрос
    request.open('POST', 'process.php');
    // при изменении состояния запроса
    request.addEventListener('readystatechange', function() {
      // если запрос завершился и код ответа сервера OK (200), то
      if (this.readyState == 4 && this.status == 200) {
        // разбираем строку json, который вернул сервер и помещаем её в переменную data
        var data = JSON.parse(this.responseText);
        // создаём переменную, в которую будем складывать результат работы (маркированный список)
        var output = '<ul>';
        // переберём объект data
        for (var key in data) {
          output += '<li><b>' + key + "</b>: " + data[key] + '</li>';
        }
        // добавим к переменной закрывающий тег ul
        output += '</ul>';
        // выведем в элемент (id = "result") значение переменной output
        document.getElementById('result').innerHTML = output;
      }
    });
    // отправляем запрос на сервер
    request.send(formData);
    // отменяем отправку формы стандартным способом
    e.preventDefault();
  });
});
</script>

Отправка объекта FormData с помощью ajax-метода библиотеки jQuery

Объект FormData можно также использовать в методе библиотеки jQuery ajax.

Для этого методу $.ajax необходимо установить следующие параметры:

processData: false,
contentType: false,

Параметр processData со значением false предотвратит автоматическое преобразование данных FormData в строку запроса. А параметр contentType со значением false запретит jQuery устанавливать заголовок Content-Type и оставит это действие объекту XMLHttpRequest. Установка этих параметров позволит предотвратить преобразование данных, закодированных объектом FormData и установку неверного заголовка (application/x-www-form-urlencoded).

Перепишем вышепредставленный код JavaScript с помощью методов библиотеки jQuery:

<script>
  // после загрузки страницы
  $(function() {
    // при нажатии на кнопку "Отправить"
    $('#message').submit(function(e) {
      // создадим объект FormData и добавим в него данные из формы
      var formData = new FormData($('#message')[0]);
      // ajax-запрос (пример использования formdata в jquery):
      //   url - адрес на который будет отправлен запрос
      //   data - данные, которые необходимо отправить на сервер
      //   processData - отменить обработку данных
      //   contentType - не устанавливать заголовок Content-Type
      //   type - тип запроса
      //   dataType - тип данных ответа сервера
      //   success - функция, которая будет выполнена после удачного запроса
      $.ajax({
        url: 'process.php',
        data: formData,
        processData: false,
        contentType: false,
        type: 'POST',
        dataType: 'JSON',
        success: function(data) {
          var output = '<ul>';
          $.each(data, function(key, value) {
            output += '<li><b>' + key + "</b>: " + value + '</li>';
          });
          output += '</ul>';
          $('#result').html(output);
        }
      });
      // отменяем отправку формы стандартным способом
      e.preventDefault();
    });
  });
</script>
Применение объекта FormData для кодирования данных формы, которые необходимо отправить с помощью AJAX на сервер в формате "multipart/form-data"
Применение объекта FormData для кодирования данных формы, которые необходимо отправить с помощью AJAX на сервер

Использование FormData для отправки файлов на сервер

Рассмотрим ещё один пример, в котором объект FormData будем использовать для отправки файла на сервер.

HTML-код, состоящий из блока (div с id="result"), элемента input с типом file и кнопки для отправки файла на сервер.

<div class="container">
  <!-- Блок, в который будем выводить путь к файлу на сервере -->
  <p class="alert alert-info">
    Результат:<br><span id="result"></span>
  </p>
  <div class="form-group">
    <!-- Элемент, для выбора файла  -->
    <input type="file" id="file">
  </div>
    <!-- Элемент для отправки файла на сервер  -->
  <button id="upload-image" class="btn btn-primary">Отправить</button>
</div>

Сценарий php, выполняющий загрузку файла в указанную директорию.

<?php
// переменная для хранения результата
$result = 'Файл не был успешно загружен на сервер';
// путь для загрузки файлов
$upload_path = dirname(__FILE__) . '/uploads/';
// если файл был успешно загружен, то
if ($_FILES['file']['error'] == UPLOAD_ERR_OK) {
  // получаем расширение исходного файла
  $extension_file = mb_strtolower(pathinfo($_FILES['file']['name'], PATHINFO_EXTENSION));
  // получаем уникальное имя под которым будет сохранён файл
  $full_unique_name = $upload_path . uniqid('file_', true).'.'.$extension_file;
  // перемещает файл из временного хранилища в указанную директорию
  if (move_uploaded_file($_FILES['file']['tmp_name'], $full_unique_name)) {
    // записываем в переменную $result ответ
    $result = 'Файл загружен и доступен по адресу: <b>/' . substr($full_unique_name, strlen($_SERVER['DOCUMENT_ROOT'])+1) . '</b>';
  } else {
    // записываем в переменную $result сообщение о том, что произошла ошибка
    $result = "Произошла обшибка при загрузке файла на сервер";
  }
}
// возвращаем результат (ответ сервера)
echo $result;
?>

JavaScript сценарий, который отправляет файл на сервер, получает от него ответ и выводит его на странице.

<script>
// после загрузки DOM модели
document.addEventListener('DOMContentLoaded', function() {
  // при нажатию на кнопку upload-image
  document.getElementById('upload-image').addEventListener('click', function() {
    // элемент, содержащий файл выбранный пользователем
    var file = document.getElementById('file');
    // элемент для вывода результата
    var result = document.getElementById('result');
    // если элемент содержит файл, то
    if (file.files.length) {
      // создаём объект formData
      var formData = new FormData();
      // добавляем в formData файл
      formData.append('file', file.files[0]);
      // создаём объект XMLHttpRequest
      var request = new XMLHttpRequest();
      // инициализирум запрос
      request.open('POST', 'process.php');
      // при изменении состояния запроса
      request.addEventListener('readystatechange', function() {
        // если запрос завершился и код ответа сервера OK (200), то
        if (this.readyState == 4 && this.status == 200) {
          // помещаем в элемент result результат ответа сервера
          result.innerHTML = this.responseText;
        }
      });
      // отправляем запрос
      request.send(formData);
    } else {
      result.innerHTML = "Не выбран файл для загрузки!";
    }
  });
});
</script>

JavaScript сценарий, переработанный с использованием методов бибилиотеки jQuery.

<script>
// после загрузки страницы
$(function() {
  // при нажатии на кнопку "Отправить"
  $('#upload-image').click(function() {
    // элемент, с помощью которого пользователь выбирает файл
    var file = $('#file');
    // элемент, в который выведим ответ сервера
    var result = $('#result');
    // если файл выбран, то
    if (file.prop('files').length) {
      // создаём объект FormData
      var formData = new FormData();
      // добавляем в объект FormData файл
      formData.append('file', file.prop('files')[0]);
      // выполняем HTTP (AJAX) запрос
      //   url - адрес, содержащий php скрипт, который будет обрабатывать запрос
      //   procedData - параметр, с помощью которого отключим преобразование данных в строку запроса
      //   contentType - параметр, с помощью которого отключим установления  типа контента jQuery
      //   type - параметр, с помощью которого установим в качестве метода отправки запроса POST
      //   success - параметр, который
      $.ajax({
        url: 'process.php',
        data: formData,
        processData: false,
        contentType: false,
        type: 'POST',
        success: function(data) {
          result.html(data);
        }
      });
    } else {
      result.html("Не выбран файл для загрузки!");
    }
  });
});
</script>
Применение объекта FormData для отправки файла на сервер посредством AJAX
Применение объекта FormData для отправки файла на сервер посредством AJAX

Комментарии: 1

Dem0n1c
Dem0n1c

Добрый день, наверняка здесь присутствует ошибка.

Метод has позволяет поверить в объекте FormData наличия указанного ключа. // данный метод вернёт true, если в FormData есть элемент с ключом key

// в противном случае он вернёт значение false

formData.delete('key');

Должно быть:formData.has('key');