2014-11-10 4 views
0

Я упростил код, чтобы сосредоточиться на важной части и описать мою проблему.Последовательное выполнение с обещаниями и вызовом AJAX

У меня есть функция с запросом AJAX, возвращающим идентификатор.

function addProposal(){ 
    var name_en = $("#name_en").val(); 
    var use_en = $("#use_en").val(); 
    var desc_en = $("#desc_en").val(); 

    $.ajax({ 
     type:'POST', 
     url:'http://localhost/index.php?option=com_test&task=addProposal&format=raw', 
     data:{ user_id: user_id, 
      name_en: name_en, 
      use_en: use_en, 
      desc_en: desc_en 
     }, 
     beforeSend:function(){ 
      $("#loading_modal").modal("show"); 
     }, 
     complete:function(){ 
      $("#loading_modal").modal("hide"); 
     }, 
     done:function(id){ 
      //------I get the ID here, when it's done---- 
      alert(id); 
      idNewProposal=id; 
     } 
    }); 
} 

Я называю эту функцию, когда пользователь нажимает на кнопку

$(document).ready(function() 
{ 
    //... 

    $(document).on('click', '#btn_add_valid', function() { 
     addProposal(); 
    }); 

    //... 
} 

Когда пользователь нажимает на эту кнопку, у меня есть еще одна функция, прикрепленную к событию, чтобы загружать файлы (см код ниже) , Моя проблема заключается в том, что мне нужно Ид сгенерированный в предыдущем вызове AJAX перед выполнением загрузки (строка «data.submit»)

$(document).ready(function() 

{ 
    //.... 

    //Function to upload file 

    $('#file-upload').fileupload({ 
     dataType: 'json', 
     autoUpload: false, 
     paramName: 'files[]', 
     maxNumberOfFiles:1, 
     add: function (e, data) { 
      //---The callback "add" is triggered each time that one file is selected 
      // I did not write all the code here but you have to know that I make some test 
      //for each selection under this callback (size and type of file). 
      //So if the user select a file which not match with the constraints, 
      //the input stay empty and an error message is displayed. 

      //--However I want to start the upload after the click on the button 
      $(document).on('click', '#btn_add_valid', function() { 
       data.formData = { id: idNewProposal}; //------I need the ID here---- 
       data.submit(); //--The upload start Here (after the click on the button, all the files are sent) 
      }); 

     }, 
     done: function (e, data) { 
       $("#loading_file").modal("hide"); 
       $("#validation_modal").modal("show"); 
     }, 
     progressall: function (e, data) { 
       var progress = parseInt(data.loaded/data.total * 100, 10); 
       $('#upload-file .bar').css(
        'width', 
         progress + '%' 
       ); 
     }, 
     fail: function (e, data) { 
       alert('Error'); 
       $("#loading_file").modal("hide"); 
     } 
    }); 

} 

Резюмируя: После нажатия на кнопку Мне нужно выполнить сначала addProposal(), и когда это будет сделано, мне нужно запустить загрузку (data.submit в $ ('# file-upload'). fileupload()) По-видимому, есть способ справиться с подобной проблемой с «обещаниями» в JQuery, но я не могу понять, как использовать его в этой ситуации.

Огромное спасибо любому, кто может помочь мне с этой проблемой.

+0

Но ваша функция 'addProposal' делает ** не **' return' ничего? – Bergi

+0

Вы правы, идентификатор не возвращается функцией, а по запросу Ajax idNewProposal = id; (когда запрос выполнен) – Lauradev

+0

Что такое плагин 'fileupload', который вы используете? Когда/как часто он вызывает обратный вызов 'add', и что такое' data'? – Bergi

ответ

1

Давайте использовать обещания.

function addProposal(){ 
    var name_en = ... 
    return $.ajax({ // note the return here, the function now returns a promise 
     ... 
     beforeSend:function(){ 
      $("#loading_modal").modal("show"); 
     }, 
     complete:function(){ 
      $("#loading_modal").modal("hide"); 
     } 
    }); 
} 

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

addProposal().then(function(result){ 
    $(..).fileupload(...) // access addProposal's data in `result` 
}) 

Теперь, вы можете сделать это на двух различных щелчков, как в вашей выборке, или просто иметь add:

 add: function (e, data) { 
     // ... 
     $(document).on('click', '#btn_add_valid', function() { 
     addProposal().then(function(res){ 
      data.formData = { id: res}; 
      data.submit(); 
     }); 
     }); 
    },... 

это вызывает addProposal каждый раз add: называется, вы можете кэшировать его в другой функции, если вы хотите, чтобы всегда вызывать addProposal раз:

var p = null; 
function cachedProposal(){ 
    return p || (p = addProposal()); 
} 

Это два самых простых способа управления вызовом addProposal, если ваша логика отличается - адаптируйте.

Обратите внимание, что addProposal, вероятно, должен принимать аргументы вместо использования глобальных переменных.

+0

@Lauradev, я не могу отлаживать ваш код удаленно. Я могу только помочь с изолированным тестовым случаем. –

+0

Вы совершенно правы, я не представил достаточно подробностей. Если я попытаюсь использовать ваше решение, это почти нормально. Существует проблема с двумя записями в базе данных каждый раз, когда я отправляю (это означает, что appProposal вызывается 2 раза). Я попытался сделать свой собственный дегузер с консолью, чтобы быть уверенным, что порядок выполнения в порядке (см. Сообщение ниже). Я продолжу искать на моей стороне. – Lauradev

+0

Хорошо, это исправлено. Я сделал ошибку с моим тестом для проверки, были ли входные файлы пустыми. Теперь все работает (изменение базы данных, создание папок, загрузка файлов, отображение сообщений). Единственное, что это сообщение об ошибке в консоли «слишком много рекурсии». Кажется, это не влияет на работу. Принимая во внимание код и след ниже, вы имеете какое-либо представление о происхождении этой ошибки? – Lauradev

0

Помещенных функции вместе:

done:function(id){ 


      //------I get the ID here, when it's done---- 
      alert(id); 
      idNewProposal=id; 

Поместите свой чек OnClick перед функцией, по-прежнему завернутый вместе, если необходимо обернуть другой OnClick элемент до этого

Я не уверен, что это OnClick должно вернуться , но эфир способом, вобще если проверка, и если это правильно запустить другую функцию ...

 $(document).on('click', '#btn_add_valid', function() { 
      addProposal().; 
     if(idNewProposal != //or equals to something){ 
proposalCheck(); // call the function 
    function proposalCheck() { 
        data.formData = { id: idNewProposal}; //------I need the ID here---- 
        data.submit(); //--The upload start Here (after the click on the button, all the files are sent) 


     $('#file-upload').fileupload({ 
       dataType: 'json', 
       autoUpload: false, 
       paramName: 'files[]', 
       maxNumberOfFiles:1, 
       add: function (e, data) { 
    ... 



     } 
    }); 
    }); 
}; 
+0

Я не могу этого сделать, потому что $ ('# file-upload'). Fileupload() должен быть меньше $ (document) .ready (function() {...}) для правильной привязки к входу [type = file] при загрузке страницы (иначе загрузка не будет работать). – Lauradev

+0

проверить мой ответ сейчас :) – SergeDirect

+0

Да, в начале я думал, что такое решение может работать, но на самом деле обе функции асинхронны. Это означает, что, когда будет нажата кнопка #btn_add_valid, обе функции будут запущены одновременно, и идентификатор не будет создан до того, как данные будут переданы. Мне нужно найти автоматический способ запуска загрузки, когда addProposal() было сделано. (Последовательное выполнение при нажатии кнопки: сначала addProposal(), а затем data.submit с параметром «idNewProposal») – Lauradev

0

Основано на решении, предложенном Бенджамином. Я написал следующие функции:

function addProposal(){ 
    //console.log("Execute AddProposal"); 
    var name_en = $("#name_en").val(); 
    var use_en = $("#use_en").val(); 
    var desc_en = $("#desc_en").val(); 

    return $.ajax({ 
     type:'POST', 
     url:'http://localhost/index.php?option=com_test&task=addProposal&format=raw', 
     data:{ user_id: user_id, 
       name_en: name_en, 
       use_en: use_en, 
       desc_en: desc_en, 
     }, 
     beforeSend:function(response){ 
       $("#loading_modal").modal("show"); 
       //console.log("AddProposal - BEFORESEND"); 
     }, 
     complete:function(response){ 
       $("#loading_modal").modal("hide"); 
       //console.log("AddProposal - COMPLETE"); 

     }, 
    }); 
} 

function cachedProposal(){ 
    //console.log("Execute cachedProposal"); 
    return p || (p = addProposal()); 
} 

И в основной функции «$ (документ).готовы (функция()», я написал этот код

$(document).ready(function() 
{ 
    p = null; 
    //.... 

    $('#file-upload').fileupload({ 
     dataType: 'json', 
     autoUpload: false, 
     paramName: 'files[]', 
     maxNumberOfFiles:1, 
     add: function (e, data) { 
      var uploadErrors = []; 
      var acceptImgTypes = /^image\/(gif|jpe?g|png)$/i; 
      var acceptDocTypes = /^application\/(pdf|msword|vnd.openxmlformats-officedocument.wordprocessingml.document)$|^text\/plain$/i; 

      //console.log("ADD FILE: "+ data.files[0].name); 

      if (data.fileInput[0].id=="file-img"){ 
       if (data.originalFiles[0]['type'] && !acceptImgTypes.test(data.originalFiles[0]['type'])) { 
        uploadErrors.push('Not an accepted file type'); 
       } 
       if (data.originalFiles[0]['size'] && data.originalFiles[0]['size'] > 4000000) { 
        uploadErrors.push('File size is too big'); 
       } 
      }else{ 
       if (data.originalFiles[0]['type'] && !acceptDocTypes.test(data.originalFiles[0]['type'])) { 
        uploadErrors.push('Not an accepted file type'); 
       } 
       if (data.originalFiles[0]['size'] && data.originalFiles[0]['size'] > 10000000) { 
        uploadErrors.push('File size is too big'); 
       } 
      } 

      if (uploadErrors.length > 0) { 
        alert(uploadErrors.join("\n")); 
      } else { 
       if (data.fileInput[0].id=="file-img"){ 
        $("#txt-file-img").val(data.files[0].name); 
       }else{ 
        $("#txt-file-doc").val(data.files[0].name); 
       } 

       $(document).on('click', '#btn_add_valid', function() { 
        cachedProposal().then(function(res){ 
         //console.log("cachedProposal-Promise : id="+res.id); 
         data.formData = {id: res.id}; 
         data.submit(); 
         //-----$("#loading_file").modal("show"); 
        }); 
       }); 

      } 
     }, 
     done: function (e, data) { 
      //-----$("#loading_file").modal("hide"); 
      $("#validation_modal").modal("show"); 
     }, 
     progressall: function (e, data) { 
      var progress = parseInt(data.loaded/data.total * 100, 10); 
      $('#upload-file .bar').css(
       'width', 
       progress + '%' 
      ); 
      $('#file-percentage').text(
        progress + '%' 
      ); 
     }, 
     fail: function (e, data) { 
       alert('Error'); 
       //-----$("#loading_file").modal("hide"); 
     } 
    }); 


    $(document).on('click', '#btn_add_valid', function() { 
     //console.log("---CLICK ON SUBMIT BUTTON---"); 
     var $img =$("#txt-file-img").val(); 
     var $doc =$("#txt-file-doc").val(); 
     if (($img == '') && ($doc == '')){ 
      // console.log("Submit - NO FILES"); 
      addProposal(); 
      $("#validation_modal").modal("show"); 
     } 
    }); 
}); 

Трассировка и результат

Сценарий: NO FILES ОТДЕЛЬНЫЕ

Трассировка:

---CLICK ON SUBMIT BUTTON--- 
Submit - NO FILES 
Execute AddProposal 
Add Proposal - BEFORESEND 
Add Proposal - COMPLETE 

Результат:

1 Запись в базе данных - NO FOLDERNO UPLOADED FILES -> OK


Выбран один файл (вход для файла изображения)

ADD FILE: capture.jpg 
---CLICK ON SUBMIT BUTTON--- 
Execute cachedProposal 
Execute AddProposal 
AddProposal - BEFORESEND 
cachedProposal-Promise : id=76 
AddProposal - COMPLETE 
ERROR too much recursion //??? 

1 запись в базе данных (ID = 76) И

1 ПАПКА создана с имя 76 и с файлом img, загруженным внутри -> OK


ОДИН ФАЙЛ ВЫБРАННЫЙ (Вход fo г док-файл)

ADD FILE: test.pdf 
---CLICK ON SUBMIT BUTTON--- 
Execute cachedProposal 
Execute AddProposal 
AddProposal - BEFORESEND 
AddProposal - COMPLETE 
cachedProposal-Promise : id=79 
AddProposal - COMPLETE" 
ERROR too much recursion //??? 

1 запись в базе данных (ID = 79) И

1 ПАПКА создается с именем 79 и с файлом док закачанный внутрь -> OK


ДВА выбранных файлов (по одному для каждого входа)

ADD FILE: capture.jpg 
ADD FILE: test.pdf 
---CLICK ON SUBMIT BUTTON--- 
Execute cachedProposal 
Execute AddProposal 
AddProposal - BEFORESEND 
Execute cachedProposal 
cachedProposal-Promise : id=80 
AddProposal - COMPLETE 
ERROR too much recursion //??? 

1 запись в базе данных (ID = 80) и

1 ПАПКА создается с именем 80 и с обеих закачанных файлов внутри -> OK


Все работает за исключением того, что у меня есть это странное сообщение об ошибке в консоли «ERROR слишком много рекурсии». Он отображается каждый раз, когда я загружаю файлы. Кто-то знает, откуда он?

EDIT: Если я прокомментирую строки с помощью $ ("# load_file"). Modal (...); Сообщение исчезает! см. код с комментариями (// -----). Я не понимаю, почему?

Смежные вопросы