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

В приложении 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 событие отправки запускается только тогда, когда рассматриваемое текстовое поле не проходит проверку, которая может произойти на клиенте. Например, если не выполняется обязательное или регулярное выражение, запускается 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 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")
}

Я также использую токен защиты от подделки, если это имеет значение. Спасибо.


person danludwig    schedule 20.10.2011    source источник
comment
Не могли бы вы также показать код модели представления и <form> из представления?   -  person Russ Cam    schedule 20.10.2011
comment
Опубликовал модель представления и отрендеренный html вместе с исходным кодом cshtml. Это проверка jquery или ненавязчивые адаптеры, которые могут добавлять атрибут novalidate?   -  person danludwig    schedule 22.10.2011
comment
Я никогда раньше не видел novalidate. Его нет в исходном коде MVC 3. Какие еще пакеты вы установили?   -  person counsellorben    schedule 22.10.2011
comment
Да, я вижу это во всех своих формах. Может быть, я должен начать новый вопрос. Пакеты в приложении MVC: AutoMapper, CommonServiceLocator, ELMAH Core Library, Elmah.Contrib.Mvc, EF4.1, jQuery, jq UI, jq Validation, jq Visual Studio 2010 Intellisense, MicrosoftWebMvc, Modernizr, Mvc Html5 Templates, Mvc2Futures, MvcScaffolding, T4MVC , T4Scaffolding, Unity, кэширование Windows Azure AppFabric, веб-роль Windows Azure.   -  person danludwig    schedule 23.10.2011
comment
Нашел, jquery.validate 1.9.0. Только что обновился. Из jquery.validate.js, строки 32 и 33: // Добавить тег novalidate, если HTML5. this.attr('новая дата', 'новая дата');   -  person danludwig    schedule 24.10.2011


Ответы (5)


Это немного взломано, но я бы посоветовал попробовать следующее.

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

Во-вторых, на вашей странице добавьте переменную флага [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
}

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

person counsellorben    schedule 20.10.2011
comment
Оооо, я не люблю интервал. Не обращайте внимания на settimeout, который я в итоге использовал. Спасибо за это, хотя, я могу попробовать это позже. - person danludwig; 22.10.2011
comment
когда я пытаюсь сделать это, я получаю неопределенное значение для pendingRequets? - person ; 07.11.2011

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

В конце концов я решил переопределить методы startRequest и stopRequest валидатора jQuery, чтобы добавить свою собственную логику. После выполнения собственной логики я просто вызываю старые методы валидатора.

// 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);
};

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

person Matt B    schedule 24.05.2012

Я обнаружил, что ломаю голову над этим прошлой ночью, и, испробовав различные подходы, я пришел к эволюции советников. Поскольку советники не работали прямо из коробки, я решил поделиться ими, чтобы у других не было такой же головной боли. Это не такое «чистое» решение, как хотелось бы (я действительно ненавижу использовать интервалы). Но вроде хватает.

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();
person John Reilly    schedule 20.01.2012

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

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

person danludwig    schedule 21.10.2011
comment
Теперь, когда я перечитал это, я понимаю, что это сломается для форм, загруженных через ajax. Отправка будет отключена, но недопустимый обработчик никогда не будет повторно включен. Придется попробовать хак советника... - person danludwig; 22.10.2011

Я прошел все подходы, все было хорошо, но мне ничего не помогло. Затем я проверяю версию System.Web.Mvc проекта модели (класса или DTO) и проекта View, там была разница в версии. Я обновляю оба до одной и той же версии, и это сработало для меня.

Я проверяю, что в html-генерации отсутствовали data-val-remote-additionalfields=.Email, например, я проверял их.

person sami ullah    schedule 29.01.2021