2017-01-18 9 views
1

私は、各ループを使用してSymfony 3 CRMの繰り返しフォームフィールドに入力された値を調べるjQueryをいくつか持っています。 $.postは、入力された値をデータベース内の重複をチェックする関数に送信し、重複している場合は配列に何かを追加します。そうでなければ空白の値を追加して重複ではないことを示します。これらの操作が完了すると、最後の配列をチェックし、エラーブロックにエラーを追加してユーザーに表示します。それぞれがajaxを呼び出している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; 

}); 

基本的には、入力した名前が有効であること、それを最初にチェックし、オフの投稿やdupesをチェック。問題は、妥当性検査を行い(それに応じてエラーを出力する)、括りチェックを無視し、最初の応答を返す前に実行するように見えることです。

エラーをフォームに追加して追加する前に、確認が完了していることを確認するにはどうすればよいですか?私は$.whenの機能をjQueryに実装しようと試みることを含め、他の解決策を試しましたが、実際に動作させる方法を理解していません。どんな助けもありがたい。

答えて

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関連のコードはまだありません。最後に、その後の際、両方のあなたが入力のあなたの二組を確認することができます(submit上)だから今

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

と:あなたは今DOM入力の束から値を取得し、配列にそれらを返す関数を書くことができますこれらは利用可能なので、結果を調べて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'への2回の呼び出しと '$ .when'での最後のブロックです。すでに推測したように、 '$ .post'呼び出しがすべて終了し、' $ .when'呼び出しがその同期を処理するまで、配列は利用できません。 – Alnitak

+0

OKですが、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.forEach'の代わりに' $ .fn.map'を使用して、 '$ .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 
}); 
関連する問題