How to use serialize in a form with File type input?

3

I have a form in html to register a product for it use ajax, when I make a serialize to the form I get all the fields of the same except for the field of type file that with FormData (), I can get this field but I like to know there is a way with serialize to obtain it.

function ajaxRequest(url, method, data, datatype, successCallback, errorCallback) {
  $.ajax({
    url: url,
    data: data,
    dataType: datatype,
    type: method,
    // cache: false,
    // contentType: false,
    processData: false,
    success: function (response) {
      eval(successCallback + '(' + JSON.stringify(response) + ')');
    },
    error: function(error){
      eval(successCallback + '(' + JSON.stringify(error) + ')');
    }
  });
}

$('#crear-producto').click(function(){
    let data = $('#nuevo-producto').serialize();
    // let file = new FormData();
    // data = {
    //   'datos': $('#nuevo-producto').serialize(),
    //   'file': file.append('imagen', $('#imagen-producto')[0])
    // };
    ajaxRequest(constants.URL.PRODUCTOS.CREAR, 'POST', data, 'json', 'successRequest', 'errorRequest');
  });

<form enctype="multipart/form-data" id="nuevo-producto">
          <div class="row">
            <div class="col-md-6">
              <label for="producto" class="control-label">Producto:</label>
              <input type="text" name="producto" id="producto" class="form-control border-green" value="{% if p is defined %}{{ p.nombre }} {% endif %}"/>
            </div>
            <div class="col-md-6">
              <label for="marca" class="control-label">Marca:</label>
              <select class="form-control get-dependency border-green" name="marca" id="marca" data-element="referencia" >
                <option selected disabled>--Seleccionar--</option>
                {% for marca in marcas %}
                    <option value="{{ marca.id }}">{{ marca.nombre }}</option>
                {% endfor %}
              </select>
            </div>
            <div class="col-md-6">
              <label for="referencia" class="control-label">Referencia:</label>
              <select class="form-control border-green" name="referencia" id="referencia">
                <option selected disabled>--Seleccionar--</option>
              </select>
            </div>
            <div class="col-md-6">
              <label for="precio" class="control-label">Valor Unidad</label>
              <input type="number" name="precio" id="precio" class="form-control border-green" />
            </div>
            <div class="col-md-6">
              <label for="unidades" class="control-label">Unidades:</label>
              <input type="number" name="unidades" id="unidades" class="form-control border-green" />
            </div>
            <div class="col-md-12"></div>
            <div class="col-md-6">
              <label for="genero" class="control-label">Genero:</label>
              <select class="form-control border-blue" name="genero" id="genero" >
                <option selected disabled>--Seleccionar--</option>
                {% for genero in generos %}
                    <option value="{{ genero.id }}">{{ genero.nombre }}</option>
                {% endfor %}
              </select>
            </div>
            <div class="col-md-6">
              <label for="estado" class="control-label">Estado:</label>
              <select class="form-control border-blue" name="estado" id="estado" >
                <option selected disabled>--Seleccionar--</option>
                {% for estado in estados %}
                    <option value="{{ estado.id }}">{{ estado.nombre }}</option>
                {% endfor %}
              </select>
            </div>
            <div class="col-md-6">
              <label for="lanzamiento" class="control-label">Lanzamiento:</label>
              <input type="date" name="lanzamiento" id="lanzamiento" class="form-control border-blue" />
            </div>
            <div class="col-md-6">
              <label for="" class="control-label" style="margin-bottom: 0 !important;">Calificación:</label><br>
              <span class="clasificacion">
                <input class="estrella" id="radio1" name="estrellas" value="5" type="radio">
                <label for="radio1" class="label-estrella">&#9733;</label>
                <input class="estrella" id="radio2" name="estrellas" value="4" type="radio">
                <label for="radio2" class="label-estrella">★</label>
                <input class="estrella" id="radio3" name="estrellas" value="3" type="radio">
                <label for="radio3" class="label-estrella">★</label>
                <input class="estrella" id="radio4" name="estrellas" value="2" type="radio">
                <label for="radio4" class="label-estrella">★</label>
                <input class="estrella" id="radio5" name="estrellas" value="1" type="radio">
                <label for="radio5" class="label-estrella">★</label>
              </span>
            </div>
            <div class="col-md-12">
              <label for="imagen-producto" class="control-label">Imagen del producto</label>
              <input type="file" name="imagen-producto" id="imagen-producto" class="form-control" />
            </div>
            <div class="col-md-12">
              <input type="button" value="Crear Producto" class="btn btn-success pull-right enviar" id="crear-producto"/>
            </div>
          </div>
        </form>
    
asked by user22090 30.03.2018 в 12:30
source

2 answers

0

There seems to be no way to do it with serialize() , for your case it can be done with FormData in the following way:

$('#crear-producto').click(function(){
    let data = new FormData($('#nuevo-producto')[0]);
    ajaxRequest(constants.URL.PRODUCTOS.CREAR, 'POST', data, 'json', 'successRequest', 'errorRequest');
});

The form information can be obtained from $_POST and the one from the $_FILES files.
It is also important to assign to the parameters the value of contentType: false because otherwise jQuery will send it as application/x-www-form-urlencoded; charset=UTF-8 which is its default value.

Your ajaxRequest function would look like this:

function ajaxRequest(url, method, data, datatype, successCallback, errorCallback) {
  $.ajax({
    url: url,
    data: data,
    dataType: datatype,
    type: method,
    // Ambos importantes para que jQuery no transforme la información
    contentType: false,
    processData: false,
    success: function (response) {
      eval(successCallback + '(' + JSON.stringify(response) + ')');
    },
    error: function(error){
      eval(successCallback + '(' + JSON.stringify(error) + ')');
    }
  });
}
    
answered by 02.04.2018 / 03:32
source
1
  

Unable to load a file and use serialize() with AJAX because you can not access the contents of a file stored on the client computer and send it in the application using javascript.

I recommend using FormData objects I'll give you an example that I use a lot.

function upload_files(url, inputFile, input_text, another_variable, form){
    //Obtenemos el campo de file del formulario 
    var archivos = $(inputFile)[0];
    var archivo = archivos.files; 
    var archivos = new FormData();

    //Para múltiples archivos 
    for(i=0; i<archivo.length; i++){
        archivos.append('archivo'+i,archivo[i]); //Añadimos cada archivo a el arreglo con un indice direfente
    }
    /**
     * Si queremos añadir alguna variable extra, por ejemplo algun campo tipo text
     */
    archivos.append('input_text', input_text);
    //Otra variable
    archivos.append('another_variable', another_variable);

    $.ajax({
        //Url_destino
        url:url,
        //Progress Bar
        xhr: function(){
            var xhr = new window.XMLHttpRequest();
            //Upload progress
            xhr.upload.addEventListener("progress", function(evt){
                if (evt.lengthComputable) {
                    var percentComplete = (evt.loaded / evt.total)*100;
                    //Do something with upload progress
                    form.find('.progress').removeClass('hidden');
                    form.find('.bar').css('width',percentComplete+'%');

                    if(percentComplete == 100){
                        setTimeout(function(){ 
                            //Progress Bar effect
                            form.find('.progress').addClass('hidden');
                            form.find('.bar').css('width','0%'); 
                        }, 1000);
                    }
                }
            }, false);
            //Download progress
            xhr.addEventListener("progress", function(evt){
                if (evt.lengthComputable) {
                    var percentComplete = evt.loaded / evt.total;
                    //Do something with download progress
                }
            }, false);
            return xhr;
        },
        type:'POST',
        contentType:false, //Debe estar en false para que pase el objeto sin procesar
        data:archivos, //Le pasamos el objeto que creamos con los archivos
        processData:false, //Debe estar en false para que JQuery no procese los datos a enviar
        cache:false,
        success: function(data){
            //Hacer algo con la data
       },
       error: function (jqXHR, exception) {
            var msg = '';
            if (jqXHR.status === 0) {
                msg = 'Not connect.\n Verify Network.';
            } else if (jqXHR.status == 404) {
                msg = 'Requested page not found. [404]';
            } else if (jqXHR.status == 500) {
                msg = 'Internal Server Error [500].';
            } else if (exception === 'parsererror') {
                msg = 'Requested JSON parse failed.';
            } else if (exception === 'timeout') {
                msg = 'Time out error.';
            } else if (exception === 'abort') {
                msg = 'Ajax request aborted.';
            } else {
                msg = 'Uncaught Error.\n' + jqXHR.responseText;
            }
            console.log(msg);
        },
    });
}

Used as follows:

$('#upload_files').submit(function(e) {
            e.preventDefault();
            var url = 'url/to/action.php';
            var input_text =  $('input[type=text]').val();
            var action_event =  $(this).find('.action_event').val();
            upload_files(url, '#files', input_text, action_event, $('#upload_files'));
            //Para borrar el formulario después de envíarlo y que todo salga ok
            $(this)[0].reset();
        });

The HTML would be something like:

<form  id="upload_files">
    <input type="file" id="files" name="files" multiple="multiple" required>
    <input type="text" autocomplete="off" required>
<div class="progress progress-striped active" style="height: 10px; box-shadow: none; margin: 0; background-color:white;" class="hidden">
                                <div class="bar"></div>
                            </div>
<input type="submit" value="Guardar">
</form>
    
answered by 01.04.2018 в 07:24