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

10.08.2018

Теги: AJAXFormDataJavaScriptjQueryPOSTWeb-разработкаXmlHttpRequestФорма

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

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

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

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

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

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

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

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

formData.append('key', 'some value');

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

formData.append('key', 'other value'); // 'key': ['some value', 'other value']

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

formData.set('key','another value'); // 'key': 'another value'

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

formData.delete('key');

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

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

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

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

Отправка данных формы

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

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

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

<!doctype html>
<html>
<head>
    <meta charset="utf-8">
    <title>FormData</title>
    <script src="jquery-2.1.1.min.js"></script>
    <script src="script.js" charset="UTF-8"></script>
</head>
<body>
    <div id="result"></div>

    <form action="handler.php" method="POST" id="message">
        <div>
            <span>Имя</span>
            <input type="text" name="name" value="">
        </div>
        <div>
            <span>Сообщение</span>
            <textarea name="message"></textarea>
        </div>
        <button type="submit">Отправить</button>
    </form>
</body>
</html>
PHP сценарий, который будет формировать ответ клиенту в формате JSON. Для создания ответа будем использовать ключи name и message суперглобального массива $_POST.

<?php
$result = array();
$result['name'] = 'Не заполнено поле name!';
$result['message'] = 'Не заполнено поле message!';

if (!empty($_POST['name'])) {
    $result['name'] = trim($_POST['name']);
}
if (!empty($_POST['message'])) {
    $result['message'] = trim($_POST['message']);
}

echo json_encode($result);

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

// после загрузки 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', 'handler.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>' + key + ' : ' + data[key] + '</li>';
                }
                // добавим к переменной закрывающий тег ul
                output += '</ul>';
                // выведем в элемент (id="result") значение переменной output
                document.getElementById('result').innerHTML = output;
            }
        });
        // отправляем запрос на сервер
        request.send(formData);
        // отменяем отправку формы стандартным способом
        e.preventDefault();
    });
});

Отправка формы с использованием jQuery

Объект FormData можно также использовать в методе $.ajax() библиотеки jQuery. Для этого методу $.ajax() необходимо установить следующие параметры:

  • processData: false,
  • contentType: false,

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

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

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

Отправка файлов на сервер

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

<!doctype html>
<html>
<head>
    <meta charset="utf-8">
    <title>FormData</title>
    <script src="jquery-2.1.1.min.js"></script>
    <script src="script.js" charset="UTF-8"></script>
</head>
<body>
    <div id="result"></div>
    
    <div>
        Выберите файл
        <input type="file" id="file">
    </div>
    <button id="button">Загрузить</button>
</body>
</html>

Сценарий php, выполняющий сохранение загруженного файла.

<?php
// переменная для хранения результата
$result = 'Файл не был загружен на сервер';
// если файл был успешно загружен
if ($_FILES['file']['error'] == UPLOAD_ERR_OK) {
    // получаем расширение исходного файла
    $ext = strtolower(pathinfo($_FILES['file']['name'], PATHINFO_EXTENSION));
    // получаем уникальное имя под которым будет сохранён файл 
    $name = md5(uniqid('', true)).'.'.$ext;
    // перемещаем файл из временного хранилища в указанную директорию
    if (move_uploaded_file($_FILES['file']['tmp_name'], 'uploads/'.$name)) {
        // записываем в переменную $result ответ
        $result = 'Файл загружен и доступен по адресу uploads/'.$name;
    } else {
        // записываем в переменную $result сообщение о том, что произошла ошибка
        $result = 'Ошибка при загрузке файла на сервер';
    }
}
// возвращаем результат (ответ сервера)
echo $result;

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

// после загрузки DOM модели
document.addEventListener('DOMContentLoaded', function() {
    // при нажатию на кнопку upload-image
    document.getElementById('button').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', 'handler.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 = 'Не выбран файл для загрузки!';
        }
    });
});

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

$(document).ready(function() {
    // при нажатии на кнопку «Отправить»
    $('#button').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]);
            // url — адрес, содержащий php сценарий, который будет обрабатывать запрос
            // processData — параметр, с помощью которого отключим преобразование данных в строку запроса
            // contentType — параметр, с помощью которого отключим установление типа контента jQuery
            // type — параметр, с помощью которого установим POST в качестве метода отправки запроса
            // success — функция, которая будет выполнена после удачного запроса
            $.ajax({
                url: 'handler.php',
                data: formData,
                processData: false,
                contentType: false,
                type: 'POST',
                success: function(data) {
                    result.html(data);
                }
            });
        } else {
            result.html('Не выбран файл для загрузки!');
        }
    });
});

Поиск: AJAX • FormData • JavaScript • POST • Web-разработка • XmlHttpRequest • jQuery • Форма

Каталог оборудования
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Производители
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Функциональные группы
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.