2017-01-18 100 views
1

我有一些jQuery,它使用每個循環來檢查在Symfony 3 CRM上的重複表單字段中輸入的值。有一個$.post它將輸入的值發送到一個函數,該函數檢查數據庫中的重複項,如果它是重複項,則會向數組中添加一些內容,否則會添加一個空值以指示它不是重複項。完成這些操作後,它會檢查最終數組並將任何錯誤添加到錯誤塊以顯示給用戶。每個jQuery調用都會在完成之前繼續運行

但是,它似乎總是空白,我相信它是因爲它運行的代碼顯示錯誤之前,它實際上完成獲取響應。

這裏是我的代碼:

$('#puppy_form').on('submit', function() { 
    var bitch_errors = []; 
    var dog_errors = []; 
    // NOTE: Bitch and dog names need to be checked differently so we know which error is assigned to which input 
    $('.check_bitch_name').each(function(i, obj) { 
     // need to check each name for validity and duplication. 
     var entered_bitch_name = obj.value; 
     var pattern = /^[a-zA-Z,.]+\s[a-zA-Z,.]+(\s[a-zA-Z,.]+){0,}$/; 
     if(!pattern.test(entered_bitch_name)) { 
      bitch_errors[i+1] = "invalid"; 
     } else { 
      // now to check for duplicates 
      $.post('/check-puppy-name', { name: entered_bitch_name } 
      ).done(function (response) { 
       if(response == 'duplicate') { 
        bitch_errors[i+1] = "duplicate"; 
       } else { 
        bitch_errors[i+1] = ""; 
       } 
      }); 
     } 
    }); 
    $('.check_dog_name').each(function(i, obj) { 
     // need to check each name for validity and duplication. 
     var entered_dog_name = obj.value; 
     var pattern = /^[a-zA-Z,.]+\s[a-zA-Z,.]+(\s[a-zA-Z,.]+){0,}$/; 
     if(!pattern.test(entered_dog_name)) { 
      dog_errors[i+1] = "invalid"; 
     } else { 
      // now to check for duplicates 
      $.post('/check-puppy-name', { name: entered_dog_name } 
      ).done(function (response) { 
       if(response == 'duplicate') { 
        dog_errors[i+1] = "duplicate"; 
       } else { 
        dog_errors[i+1] = ""; 
       } 
      }); 
     } 
    }); 


    if(count(bitch_errors) == 0 && count(dog_errors) == 0) { 
     return true; 
    } 

    // loop through the errors and assign them to the correct input 
    $.each(bitch_errors, function(key, value) { 
     if (value == "invalid") { 
      $('input[name="bitch_name['+key+']"]').parent().addClass('has-error'); 
      $('input[name="bitch_name['+key+']"]').next('.error-message').html('Names must be at least two words, and only contain letters'); 
      return false; 
     } else if(value == "duplicate") { 
      $('input[name="bitch_name['+key+']"]').parent().addClass('has-error'); 
      $('input[name="bitch_name['+key+']"]').next('.error-message').html('Sorry, this name has already been taken'); 
      return false; 
     } 
    }); 
    $.each(dog_errors, function(key, value) { 
     if(value != "") { 
      if (value == "invalid") { 
       $('input[name="dog_name['+key+']"]').parent().addClass('has-error'); 
       $('input[name="dog_name['+key+']"]').next('.error-message').html('Names must be at least two words, and only contain letters'); 
       return false; 
      } else if(value == "duplicate") { 
       $('input[name="dog_name['+key+']"]').parent().addClass('has-error'); 
       $('input[name="dog_name['+key+']"]').next('.error-message').html('Sorry, this name has already been taken'); 
       return false; 
      } 
     } 
    }); 

    return false; 

}); 

基本上,它首先檢查輸入的名稱是否有效,然後投遞過和愚弄檢查。問題是,即使它進行了有效性檢查(並相應地打印了錯誤),它似乎忽略了欺騙檢查並繼續進行,甚至還沒有回覆第一個響應。

我該如何確定它在完成之前檢查並將錯誤添加到表單中?我試過其他解決方案,包括嘗試在jQuery中實現$.when功能,但我並不真正瞭解如何使其工作。任何幫助讚賞。

回答

2

首先,編寫返回異步承諾給你一個價值一個狗功能:

function checkDog(name) { 
    var pattern = /^[a-zA-Z,.]+\s[a-zA-Z,.]+(\s[a-zA-Z,.]+){0,}$/; 
    if(!pattern.test(name)) { 
     return $.Deferred().resolve("invalid"); 
    } else { 
     return $.post('/check-puppy-name', { name: name }) 
     .then(function (response) { 
      if (response === 'duplicate') { 
       return 'duplicate'; 
      } else { 
       return ''; 
      } 
     }); 
    } 
} 

然後,你可以寫一個處理多個犬也,返回一個承諾(這將不會被解決,直到每一隻狗都被檢查):

function checkDogs(array) { 
    return $.when.apply($, array.map(checkDog)); 
} 

請注意,目前還沒有與DOM相關的代碼。現在,您可以編寫從一堆DOM輸入獲取值和數組返回它們的功能:終於所以現在

function getInputValues($selector) { 
    return $selector.get().map(function(el) { 
     return el.value; 
    }); 
} 

(上submit),你可以檢查你的兩組輸入,然後當兩個這些都可用,你可以檢查結果並更新DOM:

$('#puppy_form').on('submit', function() { 

    var bitch_names = getInputValues($('.check_bitch_name')); 
    var dog_names = getInputValues($('.check_dog_name')); 

    var bitch_promises = checkDogs(bitch_names); 
    var dog_promises = checkDogs(dog_names); 

    $.when(bitch_promises, dog_promises).then(function(bitch_errors, dog_errors) { 
     // update the DOM based on the passed arrays 
     ... 
    }); 
}); 
+0

我真的不明白這一點 - checkDogs的含義是什麼?如果我寫這個,這意味着之後沒有別的東西會運行,因爲它有回報嗎? –

+0

@MichaelEmerson唯一需要在你的'submit'回調中的位是兩個調用'checkInputs'和最後一個'$ .when'的塊。正如你已經猜測的那樣,直到'$ .post'調用全部完成之後,這些數組纔可用,'$ .when'調用處理該同步。 – Alnitak

+0

好吧,那很好,但checkDogs(數組)是什麼?如果我補充一點,它會在第一個括號之前拋出一個錯誤,指出「期待換行符或分號」。另外,由於返回,getInputValues永遠不會被達到? –

0

你說得對,ajax調用就像他們的名字說異步。因此,您只能依靠.done函數。一個簡單的解決方案是在母狗和狗的開始初始化一個計數器變量,並在相應的函數中減小它直到它達到零。然後,在done函數中,您還輸入一個調用錯誤數組驗證的if。這是未經測試的代碼來說明我的意思:

$('#puppy_form').on('submit', function() { 

    /* 
     here you get the initial count for bitches and dogs 
    */ 
    var bitch_count = $('.check_bitch_name').length; 
    var dog_count = $('.check_dog_name').length; 

    var bitch_errors = []; 
    var dog_errors = []; 
    // NOTE: Bitch and dog names need to be checked differently so we know which error is assigned to which input 
    $('.check_bitch_name').each(function(i, obj) { 
     // need to check each name for validity and duplication. 
     var entered_bitch_name = obj.value; 
     var pattern = /^[a-zA-Z,.]+\s[a-zA-Z,.]+(\s[a-zA-Z,.]+){0,}$/; 
     if(!pattern.test(entered_bitch_name)) { 
      bitch_errors[i+1] = "invalid"; 
     } else { 
      // now to check for duplicates 
      $.post('/check-puppy-name', { name: entered_bitch_name } 
      ).done(function (response) { 
       if(response == 'duplicate') { 
        bitch_errors[i+1] = "duplicate"; 
       } else { 
        bitch_errors[i+1] = ""; 
       } 

       /* 
        now on every checked name you decrement the counter 
        and if both counters reach zero you can be sure you 
        checked all and only now you call your validation 
       */ 
       bitch_count--; 
       if(bitch_count === 0 && dog_count === 0) { 
        return validateErrors(); 
       } 

      }); 
     } 
    }); 
    $('.check_dog_name').each(function(i, obj) { 
     // need to check each name for validity and duplication. 
     var entered_dog_name = obj.value; 
     var pattern = /^[a-zA-Z,.]+\s[a-zA-Z,.]+(\s[a-zA-Z,.]+){0,}$/; 
     if(!pattern.test(entered_dog_name)) { 
      dog_errors[i+1] = "invalid"; 
     } else { 
      // now to check for duplicates 
      $.post('/check-puppy-name', { name: entered_dog_name } 
      ).done(function (response) { 
       if(response == 'duplicate') { 
        dog_errors[i+1] = "duplicate"; 
       } else { 
        dog_errors[i+1] = ""; 
       } 

       /* 
        same here 
       */      
       dog_count--; 
       if(bitch_count === 0 && dog_count === 0) { 
        return validateErrors(); 
       } 

      }); 
     } 
    }); 
} 

/* 
    ...and finally all code that should be processed after the ajax calls 
*/ 
function validateErrors() { 
    if(count(bitch_errors) == 0 && count(dog_errors) == 0) { 
     return true; 
    } 

    // loop through the errors and assign them to the correct input 
    $.each(bitch_errors, function(key, value) { 
     if (value == "invalid") { 
      $('input[name="bitch_name['+key+']"]').parent().addClass('has-error'); 
      $('input[name="bitch_name['+key+']"]').next('.error-message').html('Names must be at least two words, and only contain letters'); 
      return false; 
     } else if(value == "duplicate") { 
      $('input[name="bitch_name['+key+']"]').parent().addClass('has-error'); 
      $('input[name="bitch_name['+key+']"]').next('.error-message').html('Sorry, this name has already been taken'); 
      return false; 
     } 
    }); 
    $.each(dog_errors, function(key, value) { 
     if(value != "") { 
      if (value == "invalid") { 
       $('input[name="dog_name['+key+']"]').parent().addClass('has-error'); 
       $('input[name="dog_name['+key+']"]').next('.error-message').html('Names must be at least two words, and only contain letters'); 
       return false; 
      } else if(value == "duplicate") { 
       $('input[name="dog_name['+key+']"]').parent().addClass('has-error'); 
       $('input[name="dog_name['+key+']"]').next('.error-message').html('Sorry, this name has already been taken'); 
       return false; 
      } 
     } 
    }); 

    return false; 

}); 
+1

我強烈推薦使用'$ .when'來代替。你也可以使用'$ .fn.map'而不是'$ .fn.forEach'生成一個承諾數組傳遞給'$ .when' – Alnitak

+0

@Alnitak我是'$ .when'的新手,所以使用作爲標誌的櫃檯是我想出的第一件事。但偷看到jquery文檔,這絕對是一條路! –

+1

查看我的答案,瞭解如何使用它的示例 – Alnitak

0

您可以使用async lib來管理這些請求,並收集,然後將被傳遞到最終的回調,你可以處理他們的成果。

我還沒有試過運行這段代碼,但希望它會讓你足夠接近,如果不是已經存在的話。

async.parallel({ 
    bitch_errors: function(callback) { 
     var bitch_errors = []; 

     async.forEachOf($('.check_bitch_name'), function(obj, i, cb) { 
      // need to check each name for validity and duplication. 
      var entered_bitch_name = obj.value; 
      var pattern = /^[a-zA-Z,.]+\s[a-zA-Z,.]+(\s[a-zA-Z,.]+){0,}$/; 
      if(!pattern.test(entered_bitch_name)) { 
       bitch_errors[i+1] = "invalid"; 
       cb(); 
      } else { 
       // now to check for duplicates 
       $.post('/check-puppy-name', { name: entered_bitch_name } 
       ).done(function (response) { 
        if(response == 'duplicate') { 
        bitch_errors[i+1] = "duplicate"; 
        } else { 
        bitch_errors[i+1] = ""; 
       } 
       cb(); 
       }); 
      } 
     }, function() { 
      callback(null, bitch_errors); 
     }); 
    }, 
    dog_errors: function(callback) { 
     var dog_errors = []; 

     async.forEachOf($('.check_dog_name'), function(obj, i, cb) { 
      // need to check each name for validity and duplication. 
      var entered_dog_name = obj.value; 
      var pattern = /^[a-zA-Z,.]+\s[a-zA-Z,.]+(\s[a-zA-Z,.]+){0,}$/; 
      if(!pattern.test(entered_dog_name)) { 
       dog_errors[i+1] = "invalid"; 
       cb(); 
      } else { 
       // now to check for duplicates 
       $.post('/check-puppy-name', { name: entered_dog_name } 
       ).done(function (response) { 
        if(response == 'duplicate') { 
         dog_errors[i+1] = "duplicate"; 
        } else { 
         dog_errors[i+1] = ""; 
        } 
        cb(); 
       }); 
      } 
     }, function() { 
      callback(null, dog_errors); 
     }); 
    } 
}, function(err, results) { 
    // you can now access your results like so 

    if(count(results.bitch_errors) == 0 && count(results.dog_errors) == 0) { 
    // ... rest of your code 
}); 
相關問題