aboutsummaryrefslogtreecommitdiff
path: root/files/ru/learn/forms/sending_forms_through_javascript
diff options
context:
space:
mode:
Diffstat (limited to 'files/ru/learn/forms/sending_forms_through_javascript')
-rw-r--r--files/ru/learn/forms/sending_forms_through_javascript/index.html391
1 files changed, 391 insertions, 0 deletions
diff --git a/files/ru/learn/forms/sending_forms_through_javascript/index.html b/files/ru/learn/forms/sending_forms_through_javascript/index.html
new file mode 100644
index 0000000000..d98ccea1ac
--- /dev/null
+++ b/files/ru/learn/forms/sending_forms_through_javascript/index.html
@@ -0,0 +1,391 @@
+---
+title: Отправка форм при помощи JavaScript
+slug: Learn/HTML/Forms/Sending_forms_through_JavaScript
+translation_of: Learn/Forms/Sending_forms_through_JavaScript
+---
+<div>{{LearnSidebar}}</div>
+
+<p><span class="seoSummary">HTML формы могут декларативно отправлять <a href="/en-US/docs/HTTP">HTTP</a>-запросы. Но формы также могут подготовить HTTP-запросы для отправки с помощью JavaScript, например при помощи <code>XMLHttpRequest</code>. В этой статье исследуются подобные подходы.</span></p>
+
+<h2 id="Формы_не_всегда_формы">Формы не всегда формы</h2>
+
+<p>В современных веб-приложениях, одностраничных приложениях и приложениях на основе фреймворков, обычно <a href="/en-US/docs/HTML/Forms">HTML-формы</a> используются для отправки данных без загрузки нового документа при получении данных ответа. В начале поговорим о том почему это требует другого подхода.</p>
+
+<h3 id="Получение_контроля_над_глобальным_интерфейсом">Получение контроля над глобальным интерфейсом</h3>
+
+<p>Отправка стандартной HTML формы, как описывалось в предыдущей статье, загружает URL-адрес, по которому были отправлены данные, это означает, что окно браузера перемещается с полной загрузкой страницы. Если избегать полную перезагрузку страницы, можно обеспечить более плавную работу, за счет предотвращения задержек в сети и возможных визуальных проблем (например, мерцания).</p>
+
+<p>Многие современные пользовательские интерфейсы используют HTML формы только для сбора пользовательского ввода, а не для для отправки данных. Когда пользователь пытатся отправить свои данные, приложение берет контроль и асинхронно передает данные в фоновом режиме, обновляя только ту часть всего интерфейса пользователя, которой требуется обновление.</p>
+
+<p>Асинхронная отправка произвольных данных обычно называется <a href="/en-US/docs/AJAX">AJAX</a>, что означает <strong>"Asynchronous JavaScript And XML" </strong>(Асинхронный JavaScript и XML).</p>
+
+<h3 id="Чем_он_отличается">Чем он отличается?</h3>
+
+<p>Объект {{domxref("XMLHttpRequest")}} (XHR) DOM может создавать HTTP-запросы, отправлять их, и получать их результат. Исторически, {{domxref("XMLHttpRequest")}} был разработан для получения и отправки <a href="/en-US/docs/XML">XML</a> в качестве формата обмена, который со временем был заменен на <a href="/en-US/docs/JSON">JSON</a>. Но ни XML, ни JSON не вписываются в кодировку запроса данных формы. Данные формы (<code>application/x-www-form-urlencoded</code>) состоят из списка пар ключ/значение в кодировке URL. Для передачи бинарных данных, HTTP-запрос преобразуется в <code>multipart/form-data</code>.</p>
+
+<div class="blockIndicator note">
+<p><strong>Замечание</strong>: Сейчас <a href="/en-US/docs/Web/API/Fetch_API">Fetch API</a> часто используется вместо XHR — это современная, обновленная версия XHR, которая работает в похожем стиле, но имеет несколько преимуществ. Большая часть XHR-кода, которую вы увидете в этой статье можно заменить на Fetch.</p>
+</div>
+
+<p>Если вы управляете фронтендом (кодом, который выполняется в браузере) и бкендом (кодом, который выполняется на стороне сервера), вы можете отправлять JSON/XML и обрабатывать их как хотите.</p>
+
+<p>Но если вы хотите использовать сторонний сервис, то вам необходимо отправлять данные в формате, который требуется сервису.</p>
+
+<p>Так как нам следует отправлять подобные данные? Ниже обписаны различные необходимые вам техники.</p>
+
+<h2 id="Отправка_данных_формы">Отправка данных формы</h2>
+
+<p>Есть три способа отправки данных формы:</p>
+
+<ul>
+ <li>Создание <code>XMLHttpRequest</code> вручную.</li>
+ <li>Использование самостоятельного <code>FormData</code> объекта.</li>
+ <li>Использование <code>FormData</code> связанного с <code>&lt;form&gt;</code> элементом.</li>
+</ul>
+
+<p>Давайте рассмотрим их подробнее:</p>
+
+<h3 id="Создание_XMLHttpRequest_вручную">Создание  XMLHttpRequest вручную</h3>
+
+<p>{{domxref("XMLHttpRequest")}} это самый безопасный и надежный способ создавать HTTPзапросы. Для отправки данных формы с помощью {{domxref("XMLHttpRequest")}}, подготовьте данные с помощью URL-кодирования, и соблюдайте специфику запросов данных формы.</p>
+
+<p>Посмотрите на пример:</p>
+
+<pre class="brush: html notranslate">&lt;button&gt;Click Me!&lt;/button&gt;</pre>
+
+<p>И на JavaScript:</p>
+
+<pre class="brush: js notranslate">const btn = document.querySelector('button');
+
+function sendData( data ) {
+ console.log( 'Sending data' );
+
+ const XHR = new XMLHttpRequest();
+
+ let urlEncodedData = "",
+ urlEncodedDataPairs = [],
+ name;
+
+ // Turn the data object into an array of URL-encoded key/value pairs.
+ for( name in data ) {
+ urlEncodedDataPairs.push( encodeURIComponent( name ) + '=' + encodeURIComponent( data[name] ) );
+ }
+
+ // Combine the pairs into a single string and replace all %-encoded spaces to
+ // the '+' character; matches the behaviour of browser form submissions.
+ urlEncodedData = urlEncodedDataPairs.join( '&amp;' ).replace( /%20/g, '+' );
+
+ // Define what happens on successful data submission
+ XHR.addEventListener( 'load', function(event) {
+ alert( 'Yeah! Data sent and response loaded.' );
+ } );
+
+ // Define what happens in case of error
+ XHR.addEventListener( 'error', function(event) {
+ alert( 'Oops! Something went wrong.' );
+ } );
+
+ // Set up our request
+ XHR.open( 'POST', 'https://example.com/cors.php' );
+
+ // Add the required HTTP header for form data POST requests
+ XHR.setRequestHeader( 'Content-Type', 'application/x-www-form-urlencoded' );
+
+ // Finally, send our data.
+ XHR.send( urlEncodedData );
+}
+
+btn.addEventListener( 'click', function() {
+ sendData( {test:'ok'} );
+} )
+</pre>
+
+<p>Это результат:</p>
+
+<p>{{EmbedLiveSample("Building_an_XMLHttpRequest_manually", "100%", 50)}}</p>
+
+<div class="note">
+<p><strong>Note:</strong> This use of {{domxref("XMLHttpRequest")}} is subject to the {{glossary('same-origin policy')}} if you want to send data to a third party web site. For cross-origin requests, you'll need <a href="/en-US/docs/HTTP/Access_control_CORS">CORS and HTTP access control</a>.</p>
+</div>
+
+<h3 id="Using_XMLHttpRequest_and_the_FormData_object">Using XMLHttpRequest and the FormData object</h3>
+
+<p>Building an HTTP request by hand can be overwhelming. Fortunately, the <a href="http://www.w3.org/TR/XMLHttpRequest/" rel="external">XMLHttpRequest specification</a> provides a newer, simpler way to handle form data requests with the {{domxref("XMLHttpRequest/FormData","FormData")}} object.</p>
+
+<p>The {{domxref("XMLHttpRequest/FormData","FormData")}} object can be used to build form data for transmission, or to get the data within a form element to manage how it's sent. Note that {{domxref("XMLHttpRequest/FormData","FormData")}} objects are "write only", which means you can change them, but not retrieve their contents.</p>
+
+<p>Using this object is detailed in <a href="/en-US/docs/DOM/XMLHttpRequest/FormData/Using_FormData_Objects">Using FormData Objects</a>, but here are two examples:</p>
+
+<h4 id="Using_a_standalone_FormData_object">Using a standalone FormData object</h4>
+
+<pre class="brush: html notranslate">&lt;button&gt;Click Me!&lt;/button&gt;</pre>
+
+<p>You should be familiar with that HTML sample. Now for the JavaScript:</p>
+
+<pre class="brush: js notranslate">const btn = document.querySelector('button');
+
+function sendData( data ) {
+ const XHR = new XMLHttpRequest(),
+ FD = new FormData();
+
+ // Push our data into our FormData object
+ for( name in data ) {
+ FD.append( name, data[ name ] );
+ }
+
+ // Define what happens on successful data submission
+ XHR.addEventListener( 'load', function( event ) {
+ alert( 'Yeah! Data sent and response loaded.' );
+ } );
+
+ // Define what happens in case of error
+ XHR.addEventListener(' error', function( event ) {
+ alert( 'Oops! Something went wrong.' );
+ } );
+
+ // Set up our request
+ XHR.open( 'POST', 'https://example.com/cors.php' );
+
+ // Send our FormData object; HTTP headers are set automatically
+ XHR.send( FD );
+}
+
+btn.addEventListener( 'click', function()
+ { sendData( {test:'ok'} );
+} )</pre>
+
+<p>Here's the live result:</p>
+
+<p>{{EmbedLiveSample("Using_a_standalone_FormData_object", "100%", 50)}}</p>
+
+<h4 id="Using_FormData_bound_to_a_form_element">Using FormData bound to a form element</h4>
+
+<p>You can also bind a <code>FormData</code> object to an {{HTMLElement("form")}} element. This creates a <code>FormData</code> object that represents the data contained in the form.</p>
+
+<p>The HTML is typical:</p>
+
+<pre class="brush: html notranslate">&lt;form id="myForm"&gt;
+ &lt;label for="myName"&gt;Send me your name:&lt;/label&gt;
+ &lt;input id="myName" name="name" value="John"&gt;
+ &lt;input type="submit" value="Send Me!"&gt;
+&lt;/form&gt;</pre>
+
+<p>But JavaScript takes over the form:</p>
+
+<pre class="brush: js notranslate">window.addEventListener( "load", function () {
+ function sendData() {
+ const XHR = new XMLHttpRequest();
+
+ // Bind the FormData object and the form element
+ const FD = new FormData( form );
+
+ // Define what happens on successful data submission
+ XHR.addEventListener( "load", function(event) {
+ alert( event.target.responseText );
+ } );
+
+ // Define what happens in case of error
+ XHR.addEventListener( "error", function( event ) {
+ alert( 'Oops! Something went wrong.' );
+ } );
+
+ // Set up our request
+ XHR.open( "POST", "https://example.com/cors.php" );
+
+ // The data sent is what the user provided in the form
+ XHR.send( FD );
+ }
+
+ // Access the form element...
+ const form = document.getElementById( "myForm" );
+
+ // ...and take over its submit event.
+ form.addEventListener( "submit", function ( event ) {
+ event.preventDefault();
+
+ sendData();
+ } );
+} );</pre>
+
+<p>Here's the live result:</p>
+
+<p>{{EmbedLiveSample("Using_FormData_bound_to_a_form_element", "100%", 50)}}</p>
+
+<p>You can even get more involved with the process by using the form's {{domxref("HTMLFormElement.elements", "elements")}} property to get a list of all of the data elements in the form and manually manage them one at a time. To learn more about that, see the example in {{SectionOnPage("/en-US/docs/Web/API/HTMLFormElement.elements", "Accessing the element list's contents")}}.</p>
+
+<h2 id="Dealing_with_binary_data">Dealing with binary data</h2>
+
+<p>If you use a {{domxref("XMLHttpRequest/FormData","FormData")}} object with a form that includes <code>&lt;input type="file"&gt;</code> widgets, the data will be processed automatically. But to send binary data by hand, there's extra work to do.</p>
+
+<p>There are many sources for binary data, including {{domxref("FileReader")}}, {{domxref("HTMLCanvasElement","Canvas")}}, and <a href="/en-US/docs/WebRTC/navigator.getUserMedia">WebRTC</a>. Unfortunately, some legacy browsers can't access binary data or require complicated workarounds. To learn more about the <code>FileReader</code> API, see <a href="/en-US/docs/Using_files_from_web_applications">Using files from web applications</a>.</p>
+
+<p>The least complicated way of sending binary data is by using {{domxref("XMLHttpRequest/FormData","FormData")}}'s <code>append()</code> method, demonstrated above. If you have to do it by hand, it's trickier.</p>
+
+<p>In the following example, we use the {{domxref("FileReader")}} API to access binary data and then build the multi-part form data request by hand:</p>
+
+<pre class="brush: html notranslate">&lt;form id="theForm"&gt;
+ &lt;p&gt;
+ &lt;label for="theText"&gt;text data:&lt;/label&gt;
+ &lt;input id="theText" name="myText" value="Some text data" type="text"&gt;
+ &lt;/p&gt;
+ &lt;p&gt;
+ &lt;label for="theFile"&gt;file data:&lt;/label&gt;
+ &lt;input id="theFile" name="myFile" type="file"&gt;
+ &lt;/p&gt;
+ &lt;button&gt;Send Me!&lt;/button&gt;
+&lt;/form&gt;</pre>
+
+<p>As you see, the HTML is a standard <code>&lt;form&gt;</code>. There's nothing magical going on. The "magic" is in the JavaScript:</p>
+
+<pre class="brush: js notranslate">// Because we want to access DOM nodes,
+// we initialize our script at page load.
+window.addEventListener( 'load', function () {
+
+ // These variables are used to store the form data
+ const text = document.getElementById( "theText" );
+ const file = {
+ dom : document.getElementById( "theFile" ),
+ binary : null
+ };
+
+ // Use the FileReader API to access file content
+ const reader = new FileReader();
+
+ // Because FileReader is asynchronous, store its
+ // result when it finishes to read the file
+ reader.addEventListener( "load", function () {
+ file.binary = reader.result;
+ } );
+
+ // At page load, if a file is already selected, read it.
+ if( file.dom.files[0] ) {
+ reader.readAsBinaryString( file.dom.files[0] );
+ }
+
+ // If not, read the file once the user selects it.
+ file.dom.addEventListener( "change", function () {
+ if( reader.readyState === FileReader.LOADING ) {
+ reader.abort();
+ }
+
+ reader.readAsBinaryString( file.dom.files[0] );
+ } );
+
+ // sendData is our main function
+ function sendData() {
+ // If there is a selected file, wait it is read
+ // If there is not, delay the execution of the function
+ if( !file.binary &amp;&amp; file.dom.files.length &gt; 0 ) {
+ setTimeout( sendData, 10 );
+ return;
+ }
+
+ // To construct our multipart form data request,
+ // We need an XMLHttpRequest instance
+ const XHR = new XMLHttpRequest();
+
+ // We need a separator to define each part of the request
+ const boundary = "blob";
+
+ // Store our body request in a string.
+ let data = "";
+
+ // So, if the user has selected a file
+ if ( file.dom.files[0] ) {
+ // Start a new part in our body's request
+ data += "--" + boundary + "\r\n";
+
+ // Describe it as form data
+ data += 'content-disposition: form-data; '
+ // Define the name of the form data
+ + 'name="' + file.dom.name + '"; '
+ // Provide the real name of the file
+ + 'filename="' + file.dom.files[0].name + '"\r\n';
+ // And the MIME type of the file
+ data += 'Content-Type: ' + file.dom.files[0].type + '\r\n';
+
+ // There's a blank line between the metadata and the data
+ data += '\r\n';
+
+ // Append the binary data to our body's request
+ data += file.binary + '\r\n';
+ }
+
+ // Text data is simpler
+ // Start a new part in our body's request
+ data += "--" + boundary + "\r\n";
+
+ // Say it's form data, and name it
+ data += 'content-disposition: form-data; name="' + text.name + '"\r\n';
+ // There's a blank line between the metadata and the data
+ data += '\r\n';
+
+ // Append the text data to our body's request
+ data += text.value + "\r\n";
+
+ // Once we are done, "close" the body's request
+ data += "--" + boundary + "--";
+
+ // Define what happens on successful data submission
+ XHR.addEventListener( 'load', function( event ) {
+ alert( 'Yeah! Data sent and response loaded.' );
+ } );
+
+ // Define what happens in case of error
+ XHR.addEventListener( 'error', function( event ) {
+ alert( 'Oops! Something went wrong.' );
+ } );
+
+ // Set up our request
+ XHR.open( 'POST', 'https://example.com/cors.php' );
+
+ // Add the required HTTP header to handle a multipart form data POST request
+ XHR.setRequestHeader( 'Content-Type','multipart/form-data; boundary=' + boundary );
+
+ // And finally, send our data.
+ XHR.send( data );
+ }
+
+ // Access our form...
+ const form = document.getElementById( "theForm" );
+
+ // ...to take over the submit event
+ form.addEventListener( 'submit', function ( event ) {
+ event.preventDefault();
+ sendData();
+ } );
+} );</pre>
+
+<p>Here's the live result:</p>
+
+<p>{{EmbedLiveSample("Dealing_with_binary_data", "100%", 150)}}</p>
+
+<h2 id="Conclusion">Conclusion</h2>
+
+<p>Depending on the browser and the type of data you are dealing with, sending form data through JavaScript can be easy or difficult. The {{domxref("XMLHttpRequest/FormData","FormData")}} object is generally the answer, and you can use a <a href="https://github.com/jimmywarting/FormData">polyfill</a> for it on legacy browsers.</p>
+
+<h2 id="See_also">See also</h2>
+
+<h3 id="Learning_path">Learning path</h3>
+
+<ul>
+ <li><a href="/en-US/docs/Learn/HTML/Forms/Your_first_HTML_form">Your first HTML form</a></li>
+ <li><a href="/en-US/docs/Learn/HTML/Forms/How_to_structure_an_HTML_form">How to structure an HTML form</a></li>
+ <li><a href="/en-US/docs/Learn/HTML/Forms/The_native_form_widgets">The native form widgets</a></li>
+ <li><a href="/en-US/docs/Learn/HTML/Forms/HTML5_input_types">HTML5 input types</a></li>
+ <li><a href="/en-US/docs/Learn/HTML/Forms/Additional_form_controls">Additional form controls</a></li>
+ <li><a href="/en-US/docs/Learn/HTML/Forms/UI_pseudo-classes">UI pseudo-classes</a></li>
+ <li><a href="/en-US/docs/Learn/HTML/Forms/Styling_HTML_forms">Styling HTML forms</a></li>
+ <li><a href="/en-US/docs/Learn/HTML/Forms/Form_validation">Form data validation</a></li>
+ <li><a href="/en-US/docs/Learn/HTML/Forms/Sending_and_retrieving_form_data">Sending form data</a></li>
+</ul>
+
+<h3 id="Advanced_Topics">Advanced Topics</h3>
+
+<ul>
+ <li><a href="/en-US/docs/Learn/HTML/Forms/Sending_forms_through_JavaScript">Sending forms through JavaScript</a></li>
+ <li><a href="/en-US/docs/Learn/HTML/Forms/How_to_build_custom_form_widgets">How to build custom form widgets</a></li>
+ <li><a href="/en-US/docs/Learn/HTML/Forms/HTML_forms_in_legacy_browsers">HTML forms in legacy browsers</a></li>
+ <li><a href="/en-US/docs/Learn/HTML/Forms/Advanced_styling_for_HTML_forms">Advanced styling for HTML forms</a></li>
+ <li><a href="/en-US/docs/Learn/HTML/Forms/Property_compatibility_table_for_form_widgets">Property compatibility table for form widgets</a></li>
+</ul>