📜 ⬆️ ⬇️

We improve the experience of interaction with forms

Often students ask me: “Which element of the site is the most important?”, To which I answer them - forms. After all, with the help of forms, users perform almost all conversion actions. It is with this element that most problems are associated. In this article I will try to tell you what can be improved when interacting with forms. And at the same time to describe the new features of working with them in browsers.

However, first I would like to indicate my position on the development of such forms. In my opinion, the right approach when developing interfaces is a progressive improvement approach.

Alexander Pershin spoke in detail about this approach in his article Progressive Enhancement . If you still have not encountered it, then I highly recommend reading it.

Another caveat: I do not think that the interface should work and look the same in all browsers. I am firmly convinced that you should not torment users with old browsers with your multi-kilo byte libraries - they are already without it.
')

Browser statistics of the RuNet


Since I will be showing approaches using new features of browsers, take a look at the current runet statistics. Everyone can determine for themselves the degree of user readiness. I divided it into two categories: full and partial support.

All receptions in this article will be estimated by 56.8% of users. In this statistics there are browsers: IE 10, Firefox 11-17, Chrome 4-24, Safari 6, Opera 12.

Some receptions will be appreciated by 80.1% of users. This additionally included support: IE 8-9, Safari 4-5, Opera 10-11.

Mobile browsers did not include statistics, although they would give an even greater percentage of support. Information was taken from LiveInternet with a slice in Russia . The average traffic for 3 months (October-December) of 2012 got into the calculation.

New HTML5 Attribute Forms


For a start, let me remind you of the new attributes of the form fields that will be used: required , autofocus , placeholder .


Along with this, many new field types have appeared: date , email , number , range and others. However, the most innocuous of them ( email ) is still used with caution. But in order for it to earn special action is not necessary. Browsers that do not know this type of field will consider it text.

There are also additional selectors in CSS: E:valid , E:invalid , E:required - with which you can describe the style design of fields in different situations.

Demonstration of the work of new attributes of fields and their design.

Such an approach, of course, will not work in older browsers. However, since we are progressively improving the shape, this should not bother us too much. The form remains to work even in older browsers. In any case, validation of the entered data should occur on the server side. Take it as a rule not to trust user data and always completely check them on the server.

Write form data as you type


One of the common problems of filling out forms is that the data entered is lost. This can happen for various reasons: site error, following the link, in the end, the Internet can be disconnected. You can solve this problem in different ways, for example, write data to localStorage as you type.

  1. if ( window. localStorage ) {
  2. var elements = document. querySelectorAll ( '[name]' ) ;
  3. for ( var i = 0 , length = elements. length ; i < length ; i ++ ) {
  4. ( function ( element ) {
  5. var name = element. getAttribute ( 'name' ) ;
  6. element. value = localStorage. getItem ( name ) || '' ;
  7. element. onkeyup = function ( ) {
  8. localStorage. setItem ( name , element. value ) ;
  9. } ;
  10. } ) ( elements [ i ] ) ;
  11. }
  12. }


Validation of the form and sending data by Ajax


Since we use the required attributes, we can also do the validation in a new way. In the HTML5 specification for the form element, the checkValidity() method has been added. It returns true or false . The form's working strategy will be very simple: if the validation check gives a negative result, we block sending the form, otherwise, we allow sending.

  1. submit. disabled = ! form. checkValidity ( ) ;


Now we add the ability to send the form without reloading, using Ajax. With the second version of the XMLHttpRequest specification, we got a lot of interesting things. For example, we can no longer engage in collecting data to submit a form, for this there is a FormData object.

  1. form. onsubmit = function ( event ) {
  2. if ( window. FormData ) {
  3. event. preventDefault ( ) ;
  4. var data = new FormData ( form ) ;
  5. var xhr = new XMLHttpRequest ( ) ;
  6. var url = form. getAttribute ( 'action' ) + '? time =' + ( new Date ( ) ) . getTime ( ) ;
  7. xhr. open ( 'post' , url ) ;
  8. xhr. onreadystatechange = function ( ) {
  9. if ( xhr. readyState == 4 && xhr. status == 200 ) {
  10. // server response: xhr.responseText
  11. }
  12. } ;
  13. xhr. send ( data ) ;
  14. }
  15. } ;


When working with asynchronous requests, be aware that some browsers cache the result. For example, this makes Internet Explorer, Mobile Safari (iOS 6) and others. To avoid this problem, you can add the current time to the request address.

Now we get the answer from the server in text form ( xhr.responseText ), but this will change over time. For example, if we know for sure that the answer is JSON, we can get a JavaScript object right away.

  1. var xhr = new XMLHttpRequest ( ) ;
  2. xhr. open ( method , url ) ;
  3. xhr. responseType = 'json' ;
  4. xhr. onreadystatechange = function ( ) {
  5. if ( xhr. readyState == 4 && xhr. status == 200 ) {
  6. // server response: xhr.response
  7. }
  8. } ;
  9. xhr. send ( ) ;


Please note that the server response will be in the xhr.response property. And the xhr.responseType property can take other values, for example: arraybuffer , blob , document .

Demonstration of saving form data and sending it using XMLHttpRequest.

After successfully submitting the form, I advise you to leave the contact information in localStorage and clear the rest. Thus, if the user wants to submit the form again, some of the information will already be filled out.

Preview of uploaded photos


Smoothly go to work with files in the forms. Until recently, there was almost no means for working with files. But everything changes. Let's start with the simple - new attributes for file upload fields.


Suppose we want to add the ability to upload several photos to our form. This field will look something like this.

  1. < input type = "file" name = "image" accept = "image / * multiple " >


I want to remind: a field with such attributes will work in older browsers. The constraint will be:

  1. Only one file;
  2. File validation is performed on the server side.

Let's try to improve the experience of interacting with files. Once we expect users to add photos, it is logical to make a preview possible. For this we will use the FileReader object from the File API specification.

  1. document. querySelector ( '[type = file]' ) . addEventListener ( 'change' , function ( ) {
  2. [ ] . forEach . call ( this . files , function ( file ) {
  3. if ( file. type . match ( /image.*/ ) ) {
  4. var reader = new FileReader ( ) ;
  5. reader. onload = function ( event ) {
  6. var img = document. createElement ( 'img' ) ;
  7. img. src = event. target . result ;
  8. div. appendChild ( img ) ;
  9. queue. push ( { file : file , element : img } ) ;
  10. } ;
  11. reader. readAsDataURL ( file ) ;
  12. }
  13. } ) ;
  14. } , false ) ;


Thus, we immediately display all selected photos on the site.



And in order to send them using Ajax, we collect them in an array queue . Earlier in the article we used the FormData object, now we just add a list of files to it.

  1. var data = new FormData ( form ) ;
  2. queue. forEach ( function ( element ) {
  3. data. append ( 'image' , element. file ) ;
  4. } ) ;


That's all, the rest remains the same. The form will be sent with files without rebooting.

Demonstration of previewing photos and sending them using Ajax.

Drag and drop files


Let's try to pay more attention to the files. Add the ability to drag files from your computer immediately to the form. In this case, the logic of previewing and sending without restarting should remain. To get started, let's select the work with the preview in a separate function.

  1. function previewImages ( files ) {
  2. [ ] . forEach . call ( files , function ( file ) {
  3. if ( file. type . match ( /image.*/ ) ) {
  4. var reader = new FileReader ( ) ;
  5. reader. onload = function ( event ) {
  6. var img = document. createElement ( 'img' ) ;
  7. img. src = event. target . result ;
  8. div. appendChild ( img ) ;
  9. queue. push ( { file : file , element : img } ) ;
  10. } ;
  11. reader. readAsDataURL ( file ) ;
  12. }
  13. } ) ;
  14. }


For example, a zone with a wrapper class will be a zone for moving files. Add events for it.

  1. var file = document. querySelector ( '[type = file]' ) ;
  2. var dropzone = document. querySelector ( '.wrapper' ) ;
  3. file. addEventListener ( 'change' , function ( ) {
  4. previewImages ( this . files ) ;
  5. this . value = '' ;
  6. } , false ) ;
  7. dropzone. addEventListener ( 'dragover' , function ( event ) {
  8. event. preventDefault ( ) ;
  9. dropzone. classList . add ( 'active' ) ;
  10. event. dataTransfer . dropEffect = 'copy' ;
  11. } , false ) ;
  12. dropzone. addEventListener ( 'drop' , function ( event ) {
  13. event. preventDefault ( ) ;
  14. dropzone. classList . remove ( 'active' ) ;
  15. previewImages ( event. dataTransfer . files ) ;
  16. } , false ) ;


As you can see, we have added the start ( dragover ) and end ( drop ) events of moving files. We transfer all transferred files to previewImages . Thus, our form works in the same way with files selected through the site and moved from the computer.

The process of downloading files (progress bar)


Photos are very large, so try to display the download process. To visualize this process, I will take the progress element, and you can take a div with a moving background. The process itself will occur in the progress event of the XMLHttpRequest specification.

  1. var xhr = new XMLHttpRequest ( ) ;
  2. xhr. upload addEventListener ( 'progress' , function ( event ) {
  3. if ( event. lengthComputable ) {
  4. progress. value = Math. round ( ( event. loaded * 100 ) / event. total ) ;
  5. }
  6. } , false ) ;


Demonstration of drag & drop and file download progress.

Eventually


Our simple form has a number of significant improvements in the UX area.

  1. Validation occurs at the time of entry;
  2. The entered data is remembered until it is sent;
  3. Contact details are saved for re-work;
  4. Photo preview;
  5. The process of downloading files.

In this case, since we acted in accordance with the progressive improvement, our form works everywhere:



Work FileReader on iOS 6.

I am sure, by improving the UX form, you can find more interesting solutions. Please add your solutions, tips, criticism in the comments below. Thank!


Original article on the Web Energy blog.

Source: https://habr.com/ru/post/163739/


All Articles