7

MVC3 アプリで、jquery の控えめな検証と [Remote] バリデーターを使用したビュー/モデル: リモート検証中、および有効なフォームがサーバーに送信されたときに、送信ボタンを無効にして待機アイコンを表示しようとしています。IE8で試すまでは、釘付けだと思っていました。

問題は、フォームが無効なときに GC と FF がフォームの送信イベントを発生させなかったため、このイベント中に送信ボタンを無効にしたことです。ただし、IE8 はフォームが無効な場合にこのイベントを発生させるため、ユーザーはフォームを再度クリックできなくなります。(IE8 はフォームを送信しませんが、イベントは発生します。)

送信ボタンのクリックイベントに関数をつけてみました。そこで、送信ボタンを無効にし、待機アイコンを表示して、次のようにしました。

$('[data-app-form-submit-button="true"]').live('click', function (e) {
    var form = $(this).parents('form');
    var icon = form.find('[data-app-form-submitting-icon="true"]');
    icon.show();
    $(this).attr('disabled', 'disabled');
    $.ajaxSetup({ async: false });
    var isValid = form.valid();
    $.ajaxSetup({ async: true });
    alert(isValid);
});

問題は、ajax セットアップ呼び出しが実際には非同期をオフにしないことです。クリック機能の外に移動すると機能しますが、すべての非同期が無効になります。代わりに、リモート検証アクション メソッドにブレークポイントを設定することによってテストされた、ページはすぐに "true" をアラートします。

何か案は?

追記:

言い忘れていましたが、IE8 では、送信イベントは、問題のテキスト ボックスがクライアントで発生する可能性のある検証に失敗した場合にのみ発生します。たとえば、required または regex に失敗すると、submit() が起動されます。リモート検証アクション メソッドの場合、それは起動されません。ただし、クライアントの検証に失敗するとすぐに、後続のリモート検証でも IE8 送信イベントがトリガーされます。

Russ Cam への返信 (コメント #1)

ビューモデルの関連コードは次のとおりです。

public class SignUpForm : IValidatableObject
{
    [DataType(DataType.EmailAddress)]
    [Display(Name = "Email Address")]
    [Required(ErrorMessage = "Email Address is required.")]
    [RegularExpression(@"^(email regex here)$",
        ErrorMessage = "This is not a valid email address.")]
    [Remote("Validate", "ControllerName", "AreaName", HttpMethod = "POST")]
    public string EmailAddress { get; set; }

    public IEnumerable<ValidationResult> Validate(
        ValidationContext validationContext)
    {

レンダリングしたものを見ていただけてうれしいです<form>。form タグと入力要素は次のようになります。

<form action="/post-action-method" method="post" novalidate="novalidate">
...
<input class="text-box single-line" data-app-focus="true" data-val="true" 
    data-val-regex="This is not a valid email address." 
    data-val-regex-pattern="^(email regex here)$" 
    data-val-remote="&amp;#39;Email Address&amp;#39; is invalid." 
    data-val-remote-additionalfields="*.EmailAddress" 
    data-val-remote-type="POST" 
    data-val-remote-url="/validate-action-method" 
    data-val-required="Email Address is required." 
    id="EmailAddress" name="EmailAddress" type="text" value=""> 
 ... 
<input type="submit" value="Submit this form" 
    data-app-form-submit-button="true" />

今まで novalidate="novalidate" 属性を見たことがありません。cshtml ファイルでは次のようになります。

@using (Html.BeginForm())
{
    @Html.EditorForModel()
    @Html.AntiForgeryToken("assault")
}

それが違いを生む場合、私は偽造防止トークンも使用しています。ありがとう。

4

5 に答える 5

3

ちょっとハックですが、次のことを試すことをお勧めします。

まず、送信ボタンを で非表示にしdisplay="none"、上記のスクリプトを実行する独自の「送信」ボタンを表示します。

次に、ページにフラグ var [ ] とcall [ ]var remotePending = false;の変数を追加し、スクリプトでフラグを true に設定してから、次の関数を使用して呼び出しますsetIntervalvar intervalPending;intervalPending = setInterval('remoteCheck()', 200);

function remoteCheck() {
    if ($.validator.pendingRequest == 0) {
        // requests are done
        // clear interval
        clearInterval(intervalPending);
        // re-enable our "submit" button

        // "click" the hidden button
        $("#hiddenSubmit").click();
    }
    // we will try again after the interval passes
}

これにより、保留中のリモート検証が完了するのを待ってから、通常どおり続行できます。私はテストしていないので、これを思い通りに動作させるには、いじる必要があるかもしれません。

于 2011-10-20T19:23:23.260 に答える
2

私はこれでテーブルに少し遅れていますが、同様の問題を解決しようとしているときにこの質問に出くわしました。私もIntervalを使いたくなかったので、別のソリューションを作成し、他の人のためにここで詳しく説明する価値があるのではないかと考えました。

結局、独自のロジックを追加するために、jQueryバリデーターのstartRequestメソッドとstopRequestメソッドをオーバーライドすることにしました。独自のロジックを実行した後、古いバリデーターメソッドを呼び出すだけです。

// Extend jQuery validator to show loading gif when making remote requests
var oldStartRequest = $.validator.prototype.startRequest;
$.validator.prototype.startRequest = function (element) {
    var container = $('form').find("[data-valmsg-for='" + element.name + "']");
    container.addClass('loading');       

    oldStartRequest.apply(this, arguments);
};

var oldStopRequest = $.validator.prototype.stopRequest;
$.validator.prototype.stopRequest = function (element) {
    var container = $('form').find("[data-valmsg-for='" + element.name + "']");
    container.removeClass('loading');

    oldStopRequest.apply(this, arguments);
};

私の目的のためにやりたかったのは、読み込み中のgifを表示するために、隣接する検証メッセージフィールドに「読み込み中」のcssクラスを追加することだけでしたが、これを簡単に拡張してボタンなどを有効/無効にすることができます。

于 2012-05-24T12:51:42.670 に答える
1

私は昨夜、これに戸惑い、さまざまなアプローチを試みた後、カウンセラーベンの進化に行き着きました. カウンセラーベンは箱から出してすぐには機能しなかったので、他の人が同じ頭痛を持つのを防ぐために共有したいと思いました. それは私が望むほど「きれいな」解決策ではありません(間隔を使用するのは本当に嫌いです)。しかし、それで十分のようです。

var iIntervalId = null;

//
// DECLARE FUNCTION EXPRESSIONS
//

//==============================================================================
// function that triggers update when remote validation completes successfully
//==============================================================================
var fnPendingValidationComplete = function () {

  var validator = $("#frmProductType").data("validator");
  if (validator.pendingRequest === 0) {

    clearInterval(iIntervalId);

    //Force validation to present to user (this will not retrigger remote validation)
    if ($("#frmProductType").valid()) {

      alert("valid - you can submit now if you like");

    }
    //else { alert("invalid"); }
  }
  //else { alert("NOT YET"); }
},

//==============================================================================
// Trigger validation
//==============================================================================
fnTriggerValidation = function (evt) {

  //Remove any cached values to ensure that remote validation is retriggered
  $("#txtProductType").removeData("previousValue");

  //Trigger validation
  $("#frmProductType").valid();

  //Setup interval which will evaluate validation (this approach because of remote validation)
  iIntervalId = setInterval(fnPendingValidationComplete, 50);
};

fnTriggerValidation();
于 2012-01-20T09:20:50.177 に答える
0

私はこれを解決しましたが、ボタンの無効化/画像表示の待機は、有効な送信フォームがある場合にのみ発生します。ただし、複数の無効なフォームの送信はべき等であるため、ユーザーは好きなだけクリックできます。(また、リモート検証アクション メソッドは、そのパラメーター値に対してキャッシュされます。)

$(function () {
    $('form').bind('invalid-form.validate', function () {
        $('form').each(function () {
            $(this).find(
                '[data-app-form-submitting-icon="true"]').hide();
            var button = $(this).find(
                'input[type="submit"][data-app-form-submit-button="true"]');
            setTimeout(function () {
                button.removeAttr('disabled');
            }, 1);
        });
    });
    $('form').live('submit', function (e) {
        $(this).find('[data-app-form-submitting-icon="true"]').show();
        var button = $(this).find(
            'input[type="submit"][data-app-form-submit-button="true"]');
        setTimeout(function () {
            button.attr('disabled', 'disabled');
        }, 0);
    });
});

これも少しハックですが、setTimeout を使用しなかった場合、送信アクションが無効なハンドラーを起動することはありませんでした。

于 2011-10-21T20:22:44.163 に答える
0

私はすべてのアプローチを試しましたが、すべてうまくいきましたが、何もうまくいきませんでした。次に、モデル(クラスまたはDTO)プロジェクトのSystem.Web.Mvcのバージョンを確認し、Viewのプロジェクトにバージョンの違いがありました。両方を同じバージョンに更新すると、うまくいきました。

HTML生成にdata-val-remote-additionalfields = ".Email"が欠落していることを確認しました。たとえば、それらを確認していました。

于 2021-01-29T12:56:15.617 に答える