Как получить ненавязчивый удаленный валидатор jquery для выполнения async..?

в приложении MVC3, используя ненавязчивую проверку jquery и представление/модель с [удаленным] валидатором: я пытаюсь отключить кнопку отправки и отобразить значок ожидания во время удаленной проверки, и когда допустимая форма отправлена на сервер. Я думал, что прибил его, пока не попробовал его в IE8.

проблема заключалась в том, что GC и FF не запускали событие отправки формы, когда форма была недействительной, поэтому я просто отключил кнопку отправки во время этого события. Однако IE8 стреляет в это событие, когда форма недействительна, в результате чего пользователь никогда не сможет щелкнуть ее снова. (IE8 не отправляет форму, но событие запускается.)

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

$('[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 на самом деле не отключает асинхронность. Это происходит, если я перемещаю его из функции click, но затем он отключает асинхронность для всего. Вместо этого страница предупреждает "true" немедленно, проверено путем установки точки останова на методе действия удаленной проверки.

какие идеи?

Дополнительная Информация:

Я забыл упомянуть, в IE8 событие submit запускается только тогда, когда текстовое поле, о котором идет речь, не проходит проверку, которая может произойти на клиенте. Например, если это не требуется или регулярное выражение, submit () запускается. Для метода действия удаленной проверки он не запускается. Однако, как только оно проверка клиента, последующие удаленные проверки также инициируют событие отправки IE8.

ответ на Russ Cam (комментарий #1)

вот соответствующий код в viewmodel:

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 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 ответов


это своего рода хаки, но я бы предложил попробовать следующее.

во-первых, скрыть кнопку Отправить с display="none", и покажите свою собственную кнопку" Отправить", которая запускает ваш скрипт выше.

во-вторых, на Вашей странице добавьте флаг var [var remotePending = false;] и переменную setInterval вызов [var intervalPending;], и в вашем скрипте установите флаг в true, затем вызовите следующую функцию, используя 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
}

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


Я немного опоздал к столу, но я наткнулся на этот вопрос, пытаясь решить подобную проблему. Я тоже не хотел использовать Interval, поэтому я приготовил другое решение и подумал, что это может быть полезно для других.

в конце концов я решил переопределить методы jQuery validator 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);
};

Все I для моих целей было просто добавить класс css "загрузка" в соседнее поле сообщения проверки, чтобы показать загрузочный gif, но вы можете легко расширить это, чтобы включить/отключить кнопку и т. д.


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();

Я в конечном итоге решил это, но кнопка disable / wait image show происходит только тогда, когда есть действительная отправленная форма. Это нормально, хотя, поскольку несколько недопустимых представлений формы являются идемпотентными, пользователь может щелкнуть столько, сколько захочет. (Кроме того, метод действия удаленной проверки кэшируется по его значениям параметров.)

$(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, действие submit никогда не запускало недопустимый обработчик.