2016-11-02 14 views
0

Я загружаю электронную таблицу для импорта данных в мою базу данных, и перед их вставкой я запускаю проверку на стороне сервера на каждое значение.jquery ждать завершения анимации до завершения ajax

Я использую JQuery Ajax, чтобы загрузить файл на сервер, и я получаю ответ обратно из обработанных данных в виде многомерного массива

var errored = false; 
var items = []; 
var width; 
var percent; 

$("#uploadForm").ajaxForm({ 
    dataType: 'json', 
    beforeSubmit: function() { 
     errored = false; 
     width = 0; 
     percent = 0; 
    }, 
    beforeSend: function() { //before sending form 
     $('#upload-progress').show(); 
    }, 
    uploadProgress: function(event, position, total, percentComplete) { //on progress 
     $('#load').width(percentComplete + '%') //update progressbar percent complete 
     $('#load').html(percentComplete + '%'); //update status text 
    }, 
    success: function(response) { 
     var size = Object.keys(response.items).length + 1; 
     //this will trigger the first callback. 
     var base = $.when({}); 
     var promises = []; 

     percent = 100/Object.keys(response.items).length; 

     $('#validate-progress').show(); 
     $('#UploadButton').html('<i class="fa fa-cog fa-spin fa-fw"></i> Validating Data'); 

     $.each(response.items, function(key, item) { 
      var last = (key == size) ? true : false; 

      promises.push(base = base.then(getAjaxDeferred(key, item, last))); 
     }); 
    }, 
    complete: function() { 
     $('#load').width('0%'); //update progressbar percent complete 
     $('#upload-progress').hide(); 
     $(this).clearForm(); 
    } 
}); 

я затем цикл через каждый из каждой строки массив и передать это функции jquery, которая использует ajax и откладывает ее до тех пор, пока она не завершится до отправки следующей строки.

function getAjaxDeferred(row, item, last) { 
    return function() { 
     // wrap with a deferred 
     var defer = $.Deferred(); 
     $.ajax({ 
      url: 'path/to/file', 
      method: 'POST', 
      data: { 
       row: row, 
       item: item 
      }, 
      dataType: 'json', 
      success: function(response) { 

       $('<p>' + response.description + ' <i class="fa fa-check"></i></p>').appendTo('#inserted-rows'); 
       items.push(response.item);     

       if(last) { 
        $('<p class="last-insert">All done!!</p>').appendTo('#inserted-rows'); 

        if(errored) { 
         $('#myModal-errors').modal('show'); 
        } 
       } 
       width = width + percent; 
       $('#validating').width(width + '%').html((Math.round(width * 10)/10).toFixed(0) + '%'); 
       $('#inserted-rows').show().animate({ scrollTop: $('#inserted-rows').prop("scrollHeight") - $('#inserted-rows').height() }, 'fast'); 
      }, 
      complete: function() { 
       // resolve when complete always. Even on failure we 
       // want to keep going with other requests 
       defer.resolve(); 
      } 
     }); 
     // return a promise so that we can chain properly in the each 
     return defer.promise(); 
    }; 
} 

Все работает точно так, как я хочу на моем сервере развития (потому что это гораздо медленнее, чем производство), строка передается функции, он проверяет на сервере, добавляет ответ на выходной DIV, обновляет прогресс ширина штриха на процент и если это последняя строка, будет отображаться модальный, если будут найдены какие-либо ошибки.

Проблема, с которой я сталкиваюсь на производственном сервере, состоит в том, что она настолько быстрая, что индикатор выполнения обновляется быстрее, чем анимация, поэтому он завершается сразу, и модальная информация появляется до завершения анимации.

Я попытался добавить полную функцию function() к анимации, которая прекратила появление модальности до тех пор, пока последняя строка не будет обработана, но это не помогло обновить индикатор выполнения.

Как я могу задержать индикатор выполнения, чтобы дождаться окончания анимации до обновления ширины, а также сделать модальное ожидание до тех пор, пока последняя строка не будет обработана?

+0

Попробуйте поместить 'defer.resolve()' в обратный вызов 'animate()' –

+0

Попробуйте ['stop (false, true)'] (https://api.jquery.com/stop/) перед 'animate() ':' $ ('# insert-rows'). show(). stop (false, true) .animate ({... '. Это завершает текущую анимацию непосредственно перед началом следующего. –

+0

' response. У элементов есть числовые ключи. Может быть, это массив, а не объект? –

ответ

1

Попробуйте stop(false, true) перед тем animate():

$('#inserted-rows').show().stop(false, true).animate({.... 

Это полный ток анимации непосредственно перед началом следующего. В противном случае анимация будет поставлена ​​в очередь и будет запускаться один за другим до завершения.