web-dev-qa-db-ja.com

jQuery Validateとマスクされた入力の間の競合

電話番号と米国の郵便番号フィールドに jQuery ValidateMasked Input の両方を使用しているフォームがあります。

たとえば、米国の郵便番号の場合、マスク入力では数字のみを入力でき、「99999」または「99999-9999」の形式を強制します(9は任意の数字です)。検証ルールも同じです。ただし、場合によっては、Validateは実際に有効であるはずのフィールドを無効としてマークします。

コードの詳細

JQuery Validateが郵便番号フィールドで使用している正規表現は_^\d{5}$|^\d{5}\-\d{4}$_です。

マスク入力で適用するマスクは.mask('99999?-9999')です

再現する手順

次のようにすると、それらの間の競合が発生します。

  • 無効な郵便番号(3桁など)を入力してください
  • フィールドから離れてタブ。マスクされた入力は入力を消去し(予想される動作)、jQuery Validateはそれが空白であるため(これも予想される)、無効としてマークします。
  • 郵便番号フィールドに戻り、有効な5桁郵便番号を入力します。
  • フィールドから離れてタブ。 まだ無効としてマークされています。これは予想外です

9桁のZipを入力しても、この問題は起こりません

仮説

このエラーは、5桁のZipの場合、マスクされた入力が一時的に「-____」を挿入して、オプションでダッシュと4桁以上を入力できることをユーザーに示すためだと思います。これはぼかしで削除されますが、アンダースコアが許可されていないため、削除される前にフィールドが検証されて失敗します。

この仮説は、フォームが後で再検証される場合、Zipフィールドが合格するという事実によってサポートされます。私はこれを2つの方法で行いました。

  • フォームを送信することにより、送信ボタンがクリックされ、Zipフィールドが通過し、フォームが送信されると、すべてのフィールドが再検証されます。
  • 特定のフィールドを再検証するblurイベントを設定する。例えば:

    $( "#zipcode")。blur(function(){$(this).closest( 'form')。validate()。element($(this));});

これはハッキーソリューションとして機能しますが、1)デフォルト設定はぼかしで既に再検証されているため、これは繰り返しです、および2)通常のValidateルールの他に追加のコードが必要です。

他の誰かがこの問題に遭遇しましたか? 追加のぼかしイベントリスナーを設定するよりもエレガントな解決策がありますか

更新:ハックソリューションの適用

上記のハッキーなソリューションを適用しても、私が望むほどうまく機能しません。たとえば、これは機能しません:

_$appDiv.delegate('input,select,textarea','blur',function(){
  $(this).closest('form').validate().element($(this));
});
_

...これもしない:

_$('input,select,textarea').live('blur',function(){
  $(this).closest('form').validate().element($(this));
});
_

...しかし、これはします:

_$('input,select,textarea').each(function(){
  $(this).blur(function(){
    $(this).closest('form').validate().element($(this));
  });
});
_

これらの要素はAJAXによって読み込まれるため、フォームセクションが読み込まれるたびに_.each_バージョンを実行する必要があります。

25
Nathan Long

私は実際にこの正確な質問に対する答えを探していました。より信頼できる回避策を考え出すことになりました。

郵便番号に対して独自のバリデーターメソッドを定義しているため、値からプレースホルダーを削除した後、郵便番号の長さが6の場合にハイフンが削除されるように変更しました。

それはこのように見えました:

$.validator.addMethod("zipcode", function(postalcode, element) {
            //removes placeholder from string
            postalcode = postalcode.split("_").join("");

            //Checks the length of the zipcode now that placeholder characters are removed.
            if (postalcode.length === 6) {
                //Removes hyphen
                postalcode = postalcode.replace("-", "");
            }
            //validates postalcode.
            return this.optional(element) || postalcode.match(/^\d{5}$|^\d{5}\-\d{4}$/);
        }, "Please specify a valid Zip code");

したがって、検証している郵便番号は、入力プラグインによってプレースホルダーが追加され、入力された郵便番号が5桁の数字(ハイフンを含めて6桁)のみの場合、ハイフンが削除されます。したがって、適切に検証されます。

10
Adrian

私は次の解決策を試してみましたが、それは魅力のように機能します。

_$("[data-input-type=phone]", "body")
  .mask("(999) 999 99 99")
  .bind("blur", function () {
    // force revalidate on blur.

    var frm = $(this).parents("form");
    // if form has a validator
    if ($.data( frm[0], 'validator' )) {
      var validator = $(this).parents("form").validate();
      validator.settings.onfocusout.apply(validator, [this]);
    }
  });
_

問題の原因はイベントの順序付けです。要素がマスクされると、blurのmaskedinputプラグインによって検証されますが、同じ要素はfocusoutイベントのバリデータープラグインによって検証されます(非IEブラウザーのブラーのラッパーです)。 maskedinputのブラーの前に呼び出されます。

この状況では、バリデーターが値をチェックするとき、input要素の値は"(___) ___ __ __"です。コードがmaskedinputのblurイベントに到達すると、プラグインは有効な入力ではないため、値をテストしてクリアします。

検証結果は、検証ケースごとに異なる場合があります。たとえば、requiredルールは、要素に値があるため、成功します。 _"999"_のようなマスクは_12__としてテストされる可能性があるため、入力を空のままにしても必須ではないnumberフィールドは失敗します

上記のコードは、マスクされた入力のフォームに検証が関連付けられているかどうかをテストし、focusoutイベントハンドラーを呼び出します。私たちのハンドラーは最新のものとして添付されているので、うまくいけばそれが最後に呼び出されるでしょう。

警告、コードは単に検証プラグインの動作をコピーします。おそらく10年間は​​機能しますが、検証プラグインが現在とは異なることを行うと決定した場合は失敗する可能性があります。

心から

11
Erdogan Kurtur

単にmask()関数にフックし、追加のロジックを追加して、デフォルトのマスクのぼかしロジックの後に独自のぼかしロジックを起動します。

//Store the original mask function
var origMaskFn = $.fn.mask;

$.fn.mask = function (mask, settings) {

    //Call the original function applying the default settings
    origMaskFn.apply(this, [mask, settings]);

    //Manually validate our element on blur to prevent unobtrusive messages
    //from showing before the mask is properly scrubbed
    $(this).bind('blur', function () {
        var $form = $(this).parents('form');
        if (!$form.exists())
            return;

        var validator = $form.validate().element($(this));
    });
}

また、 'exists()'関数に気づくかもしれません。これは、jQueryセレクターでよく使用するものです。

//Function to detect if a jQuery elements exists.  i.e.:
//      var $element = $(selector);
//      if($element.exists()) do something...

$.fn.exists = function () {
    return this.length !== 0;
}
7
Greg H

同様の問題があり、デフォルトのプレースホルダー文字を空の文字列に変更することで解決できました。

私は.mask('9?99');を使用していて、単純な「数値」ルールで検証しており、同じ種類の競合が発生していました。

マスク宣言を.mask('9?99',{placeholder:''});に変更しました...これ以上競合しません。 :)

マスクプラグインによってフォームに常に挿入される郵便番号の-が原因で、問題が発生する可能性があります。私はあなたが正規表現を^\d{5}\-$|^\d{5}\-\d{4}$に変更できると思います(どちらの場合もダッシュに一致します)。

とにかく、あなたはしばらく前に投稿し、おそらくこれはもう必要ありませんが、おそらく他の人を助けるでしょう。 :)

5
Miguel Pinto

バインディングを行う順序は重要ですか?たとえば、間に違いはありますか

$(function() {
  var $form = $("#myForm"), $Zip = $("#Zip");
  $Zip.mask("99999?-9999");
  $form.validate();
});

そして

$(function() {
  var $form = $("#myForm"), $Zip = $("#Zip");
  $form.validate();
  $Zip.mask("99999?-9999");
});

ビンディングは順番に発砲するべきだと思います。

1
Jarrett Meyer

私はいくつかの解決策を試しましたが、どれもうまくいきませんでした。私は「bootstrapValidator」( http://bootstrapvalidator.com/ )と「jquery.maskedinput」( http:/ /digitalbush.com/projects/masked-input-plugin/ )なので、誰かがまだこの問題を抱えている場合、私の解決策は:

私の入力は次のようにマークされました:

<input type="text" class="form-control" id="telefone" placeholder="(__) ____-_____" name="telefone" required>

そして、このような完全なスクリプト:

$(document).ready(function() {
   var telefone = $('#telefone'), //THAT'S MY INPUT WITH MASK
       form = telefone.parents("form"), //THAT'S MY FORM WITH THE VALIDATE
       alteredField = false; //THAT'S A FLAG TO SSE IF THE INPUT WAS ALTERED

            // APPLY MY MASK
            telefone.mask('(99) 9999-9999?9');

            // FOCUS ON ANY INPUT
            form.find('input[type=text]').focus(function(){
                // REMOVE THE VALIDATION STATUS
                $(form).data('bootstrapValidator').updateStatus($(this).attr('name'), 'NOT_VALIDATED');
                // ENABLE THE SUBMIT BUTTON
                $(form).data('bootstrapValidator').disableSubmitButtons(false);
            });

            // FOCUS ON THE MASKED INPUT
            telefone.focus(function(){
                // DISABLE THE VALIDATE
                $(form).data('bootstrapValidator').enableFieldValidators('telefone', false);
                // ENABLE THE SUBMIT BUTTON
                $(form).data('bootstrapValidator').disableSubmitButtons(false);
            }).blur(function(){ // BLUR ON THE MASKED INPUT
                // GET THE INPUT VALUE
                var value = telefone.val();
                // ENABLE THE VALIDATE 
                $(form).data('bootstrapValidator').enableFieldValidators('telefone', true);
                // CHECK IF THE VALUE IS EMPTY
                if(value != ""){
                    // CHANGE THE STATUS OF THE INPUT TO VALID 
                    $(form).data('bootstrapValidator').updateStatus('telefone', 'VALID')
                    // ACTIVE THE FLAG
                    alteredField = true;
                }else if (alteredField) { // IF THE INPUT WAS ALTERED BEFORE AND DON'T HAVE VALUE
                    // CHANGE THE STATUS OF THE INPUT TO INVALID
                    $(form).data('bootstrapValidator').updateStatus('telefone', 'INVALID')
                };
            });

        });

このコードは「bootstrapValidator」の標準的な動作を変更しますが、私がバグを解決するために得た唯一の方法でした。

パフォーマンスの問題についてはわかりません。コードを変更して改善してください^^この情報がお役に立てば幸いです^ _ ^

私は同じ問題に直面し、適切な解決策をとるために2時間を費やしました。最後に、適切なコードを作成しました。使えます

郵便番号の場合。

$.validator.addMethod("zipcode", function(postalcode, element) {
            //removes placeholder from string
            postalcode = postalcode.replace(/[^0-9]/g, "");
            //validates postalcode.
            return this.optional(element) || postalcode.match(/^\d{5}$|^\d{5}\-\d{4}$/);
        }, "Please specify a valid Zip code");

Zipの長さを増減する場合は、postalcode.match(/ ^\d {5} $ | ^\d {5}-\ d {4} $ /);を変更します。あなたの要件に応じて番号。

電話の場合は同じコードが使用されますが、postalcode.match(/ ^\d {10} $ | ^\d {10}-\ d {9} $ /);のような番号のみを変更する必要があります。

$.validator.addMethod("phone_length", function(phoneno, element) {
                //removes all special characters
                phoneno= phoneno.replace(/[^0-9]/g, "");
                return this.optional(element) || phoneno.match(/^\d{10}$|^\d{10}\-\d{9}$/);
            }, "Please enter a valid phone");

このコードがあなたのお役に立てば幸いです。呼び出し方法を知りたい場合は、検証フィールドにzipcode:trueを追加するだけです

0