Подтвердить что ты не робот

Проверка jquery, не ожидающая, что удаленная проверка вернет true, считает, что форма действительна

$("#new_component_form").validate({
  errorClass: 'input-error',
  rules : {
    "comp_data[account_name]" : {
      required: true,
      remote: {
        url: "/validate",
        data: {
          provider: 'twitter'
        }
      }
    }
  },
  onsubmit: true,
  onfocusout: false,
  onkeyup: false,
  onclick: false
});



 $("#new_component_form").submit(function(){
    console.log($(this).valid());

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

4b9b3361

Ответ 1

Как и в случае jQuery Validate 1.11.1 (и, возможно, даже старше), принятый ответ не работает. Кроме того, на этот вопрос нет простого ответа, и для решения требуется добавить специальный метод проверки для проверки jQuery.

На самом деле простой ответ может быть просто: Не называть valid() вручную, если все, что вы хотите сделать, это отправить форму. Просто пусть плагин Validate сделает это за вас. Внутри он будет ожидать завершения всех асинхронных запросов, прежде чем разрешить отправку формы. Эта проблема возникает только при ручной проверке valid() или element().

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

Итак, почему настройка async: false не работает? Если вы установите async на false, запрос будет выполнен синхронно, однако плагин не справится с этим правильно. Внутренняя функция remote всегда возвращает "pending", которая приведет к возврату функции valid() true, даже если запрос уже завершен и получен ложный ответ! Он не проверяет значение ответа или показывает ошибку до конца.

Решение о создании valid() и element() ведет себя синхронно при использовании синхронного обратного вызова - это добавить специальный метод проверки. Я пробовал это сам, и он работает нормально. Вы можете просто скопировать исходный код из обычной удаленной проверки и изменить его для обработки синхронных вызовов ajax и по умолчанию быть синхронными.

Исходный код удаленной функции в v1.11.1 начинается в строке 1112 jquery.validate.js:

remote: function( value, element, param ) {
    if ( this.optional(element) ) {
        return "dependency-mismatch";
    }

    var previous = this.previousValue(element);
    if (!this.settings.messages[element.name] ) {
        this.settings.messages[element.name] = {};
    }
    previous.originalMessage = this.settings.messages[element.name].remote;
    this.settings.messages[element.name].remote = previous.message;

    param = typeof param === "string" && {url:param} || param;

    if ( previous.old === value ) {
        return previous.valid;
    }

    previous.old = value;
    var validator = this;
    this.startRequest(element);
    var data = {};
    data[element.name] = value;
    $.ajax($.extend(true, {
        url: param,
        mode: "abort",
        port: "validate" + element.name,
        dataType: "json",
        data: data,
        success: function( response ) {
            validator.settings.messages[element.name].remote = previous.originalMessage;
            var valid = response === true || response === "true";
            if ( valid ) {
                var submitted = validator.formSubmitted;
                validator.prepareElement(element);
                validator.formSubmitted = submitted;
                validator.successList.push(element);
                delete validator.invalid[element.name];
                validator.showErrors();
            } else {
                var errors = {};
                var message = response || validator.defaultMessage( element, "remote" );
                errors[element.name] = previous.message = $.isFunction(message) ? message(value) : message;
                validator.invalid[element.name] = true;
                validator.showErrors(errors);
            }
            previous.valid = valid;
            validator.stopRequest(element, valid);
        }
    }, param));
    return "pending";
}

Обратите внимание, что он всегда возвращает "ожидание", даже если вызов ajax завершен.

Чтобы устранить эту проблему, внесите следующие изменения:

  • Переместить объявление переменной valid за пределы вызова ajax и функцию успеха, чтобы сделать закрытие, и присвоить ему значение по умолчанию "pending".
  • Измените старое объявление переменной valid на назначение.
  • Вернуть переменную valid вместо константы "pending".

Вот полный код для плагина к плагину. Просто сохраните это как файл js и включите его в свою страницу или шаблон после включения для проверки jQuery:

//Created for jQuery Validation 1.11.1
$.validator.addMethod("synchronousRemote", function (value, element, param) {
    if (this.optional(element)) {
        return "dependency-mismatch";
    }

    var previous = this.previousValue(element);
    if (!this.settings.messages[element.name]) {
        this.settings.messages[element.name] = {};
    }
    previous.originalMessage = this.settings.messages[element.name].remote;
    this.settings.messages[element.name].remote = previous.message;

    param = typeof param === "string" && { url: param } || param;

    if (previous.old === value) {
        return previous.valid;
    }

    previous.old = value;
    var validator = this;
    this.startRequest(element);
    var data = {};
    data[element.name] = value;
    var valid = "pending";
    $.ajax($.extend(true, {
        url: param,
        async: false,
        mode: "abort",
        port: "validate" + element.name,
        dataType: "json",
        data: data,
        success: function (response) {
            validator.settings.messages[element.name].remote = previous.originalMessage;
            valid = response === true || response === "true";
            if (valid) {
                var submitted = validator.formSubmitted;
                validator.prepareElement(element);
                validator.formSubmitted = submitted;
                validator.successList.push(element);
                delete validator.invalid[element.name];
                validator.showErrors();
            } else {
                var errors = {};
                var message = response || validator.defaultMessage(element, "remote");
                errors[element.name] = previous.message = $.isFunction(message) ? message(value) : message;
                validator.invalid[element.name] = true;
                validator.showErrors(errors);
            }
            previous.valid = valid;
            validator.stopRequest(element, valid);
        }
    }, param));
    return valid;
}, "Please fix this field.");

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

Чтобы использовать это, просто замените "remote" в настройках проверки на "synchronousRemote" везде, где вы хотели бы использовать это. Например:

$("#someForm").validate({
    rules: {
        someField: {
            required: true,
            synchronousRemote: {
                    url: "/SomePath/ValidateSomeField"
                    //notice that async: false need not be specified. It the default.
            }
        }
    },
    messages: {
        someField: {
            required: "SomeField is required.",
            synchronousRemote: "SomeField does not exist."
        }
    },
    onkeyup: false,
    onfocusout: false
});

Ответ 2

Включение в ту же проблему кажется, что у вас установлен удаленный вызов синхронно - async: false

В противном случае $("form").valid() вернет true для удаленной проверки, см. ниже, что я использую

rules: {
    NameToValidate: {
        required: true,
        remote: function()
        {
            return {
            type: "POST",
            async: false,
            url: "www.mysite.com/JSONStuff",
            contentType: "application/json; charset=utf-8",
            dataType: "json",
            data: JSON.stringify( {
                Name: "UNIQUE NAME"
            } )
        }
    }
},
.....

Ответ 3

Вот решение, которое мы придумали в моем проекте.

var validPendingTimeout;

function doSomethingWithValid() {
  var isValid = $("#form").valid();
  var isPending = $("#form").validate().pendingRequest !== 0;

  if (isPending) {
    if (typeof validPendingTimeout !== "undefined") {
      clearTimeout(validPendingTimeout);
    }
    validPendingTimeout = setTimeout(doSomethingWithValid, 200);
  }

  if (isValid && !isPending) {
    // do something when valid and not pending
  } else {
    // do something else when not valid or pending
  }
}

Это использует тот факт, что $( "# form" ). validate(). pendingRequest всегда будет > 0 всякий раз, когда есть удаленная проверка.

Примечание. Это не будет работать с установкой async: true в удаленном запросе.

Ответ 4

Самый простой способ исправить эту проблему (здесь сообщается: https://github.com/jzaefferer/jquery-validation/issues/361) - проверить дважды, если форма действительна:

if (myForm.valid() && myForm.valid()) {
    ...
}

Настройка удаленных правил на async:false и проверка достоверности с помощью valid() на самом деле ожидает завершения вызовов, но их возвращаемые значения не используются. Вызов valid() снова учитывает их.

Немного уродливый, но он работает. Я использую jquery 2.1.0 и jquery-validation 1.11.1, BTW.

Ответ 5

Вы должны остановить обычный прием браузера, если проверка вернет false.

$("#new_component_form").submit(function() {
    if ($(this).valid())) {
        console.log("I'm a valid form!");
    } else {
        console.log("I'm NOT a valid form!");
        //Stop the normal submit of the browser
        return false;
    }
}