【问题标题】:jQuery validate postalcode fill cityjQuery验证邮政编码填写城市
【发布时间】:2017-03-15 14:11:03
【问题描述】:

我正在为我的表单使用 jQuery 验证,并且我有一个邮政编码的自定义规则。我正在使用 API 检查邮政编码,如果正确,则必须填写 <input type="text" name="city"> 字段。我有这个代码:

$.validator.addMethod('postalcode', function(value, $elem) {
    var is_success = false;

    $.ajax({
        url: '/ajax/check_postal_code.php',
        data: {postal_code: value},
        json: true,
        async: false,
        success: function(msg) {
            is_success = msg.status === 'OK'

            if (is_success) {
                $('input[name="city"]').val(msg.results[0].address_components[1].long_name);
                $('input[name="city"]').valid();
            }
        }
    });

    return is_success;
}, 'Please enter a VALID postal code');

现在这可以正确执行 AJAX 调用,但是,它不会“验证”邮政编码字段。它只验证我的地址、验证码和城市字段(由代码完成)。

如果我删除$('input[name="city"]').valid();,它会验证所有内容,但不会检测到$('input[name="city"]').val(msg.results[0].address_components[1].long_name);。 (它会填充输入,但会出现错误,您需要插入城市)。

如何填写城市并与整个表格一起验证?


这不是重复的,因为我的 AJAX 调用是同步的,但是当我操作输入并将数据放入其中时,jQuery 验证不会看到更改并说您必须插入一个值。如果我在操作字段后手动验证字段,则某些字段将不再被验证。

【问题讨论】:

标签: jquery validation


【解决方案1】:

我相信至少有一个问题是从 .addMethod() 中调用 .valid()。将其包装在 setTimeout 中似乎效果更好。

https://codepen.io/anon/pen/mWqJbo?editors=1011

HTML:

<form id='addressForm'>
  <input id='postalcode' type='postalcode' name='postalcode' placeholder='postal code' />
  <br/>

  <input name='city' required placeholder='city' />
  <br/>

</form>
<button id='submit'>submit</button>

<div id='success' style='display:none'>Success</div>

JS:

var myUrl = "https://api.zippopotam.us/us/";
var postalcode = ''

$('input[name=postalcode]').on('change', function() {
  $('#success').hide();
  $(this).valid();
});

$('#submit').on('click', function() {
  $('#success').hide();
  if ($('#addressForm').valid()) {
    $('#success').show();
  }
});

//init jquery validation
$("#addressForm").validate({
  messages: {
    postalcode: 'Please enter a valid postal code'
  },
  rules: {
    postalcode: {
      required: true,
      postalcode: true
    },
    city: {
      required: true,
    }
  }
});

$.validator.addMethod('postalcode', function(value, $elem) {
  /* don't re-validate postalcode on submit - 
  saves time & prevent edits to the city field from being overwritten.
  If edits to city shouldn't be allowed, make city field readonly.
  Note that many zipcodes map to multiple cities (at least in the US).  You may want to present
  user with a selectable list in those cases.
  */
  if (postalcode && value === postalcode) {
    return true;
  }

  var is_success = false;
  var city = ''

  $.ajax({
    url: myUrl + $('input[name=postalcode]').val(),
    data: {
      postal_code: value
    },
    json: true,
    async: false,
    success: function(response) {
      is_success = typeof(response['post code']) !== 'undefined';
      city = response.places[0]['place name'];
    },
    error: function(err) {
      //zippopotam api returns 404 if zip is invalid
      if (err.status === 404) {
        //clear last valid postal code
        postalcode = '';
        $('input[name=city]').val('');
        $('#success').hide();
      }

      //fixme handle other errors / notify user
      console.log('error ' + JSON.stringify(err));
    }
  });

  if (is_success) {
    $('input[name=city]').val(city);

    //remember last valid postal code
    postalcode = $('input[name=postalcode]').val();

    //previous error message(s) may not be cleared if .valid() is called from within .addMethod()
    setTimeout(function() {
      $('input[name="city"]').valid();
    }, 1);
  }    
  return is_success;
}, 'Please enter a VALID postal code');

您的代码使用同步 ajax,这通常不是一个好主意。如果你想让它异步,你需要使用jquery validation remote method

但是,如果数据有效,该方法假定 ajax 响应将返回“true”。您需要能够修改后端,以便有一个“有效”端点,如果邮政编码有效,该端点将返回 true。我相信您还需要添加第二个端点来返回相应的城市。

您可以使用自定义实现覆盖它,而不是让您的后端符合 remote 的要求。

这是一个示例 (codepen):

HTML:

<form id='addressForm'>
  <input id='postalcode' type='postalcode' name='postalcode'  placeholder='postal code'/>
  <br/>
  <input name='city' required placeholder='city'/>
  <br/>
</form>

<button id='submit'>submit</button>

<div id='success' style='display:none'>Success</div>

JS:

//override
$.validator.methods.remote = function(value, element, param, method) {
  //zippopotam specific
  param.url = myUrl + value;

  if (this.optional(element)) {
    return "dependency-mismatch";
  }

  method = typeof method === "string" && method || "remote";

  var previous = this.previousValue(element, method),
    validator, data, optionDataString;

  if (!this.settings.messages[element.name]) {
    this.settings.messages[element.name] = {};
  }
  previous.originalMessage = previous.originalMessage || this.settings.messages[element.name][method];
  this.settings.messages[element.name][method] = previous.message;

  param = typeof param === "string" && {
    url: param
  } || param;
  optionDataString = $.param($.extend({
    data: value
  }, param.data));
  if (previous.old === optionDataString) {
    return previous.valid;
  }

  previous.old = optionDataString;
  validator = this;
  this.startRequest(element);
  data = {};
  data[element.name] = value;
  $.ajax($.extend(true, {
    mode: "abort",
    port: "validate" + element.name,
    dataType: "json",
    data: data,
    context: validator.currentForm,
    success: function(response) {
      //zippopotam specific -> write your own definition of valid
      var valid = typeof(response['post code']) !== 'undefined',
        errors, message, submitted;
      ///////////////

      validator.settings.messages[element.name][method] = previous.originalMessage;
      if (valid) {
        //your code here
        $('input[name=city]').val(response.places[0]['place name'])

        //end your code 

        submitted = validator.formSubmitted;
        validator.resetInternals();
        validator.toHide = validator.errorsFor(element);
        validator.formSubmitted = submitted;
        validator.successList.push(element);
        validator.invalid[element.name] = false;
        validator.showErrors();
      } else {
        //your code here if api returns successfully with an error object

        //end your code
        errors = {};
        message = response || validator.defaultMessage(element, {
          method: method,
          parameters: value
        });
        errors[element.name] = previous.message = message;
        validator.invalid[element.name] = true;
        validator.showErrors(errors);
      }
      previous.valid = valid;
      validator.stopRequest(element, valid);
    },
    error: function(response) {
      //your code here if api fails on bad zip, e.g. zippopotam returns 404
      if (response.status === 404) {
        $('input[name=city]').val('');
        //end your code
        errors = {};
        message = validator.defaultMessage(element, {
          method: method,
          parameters: value
        });
        errors[element.name] = previous.message = message;
        validator.invalid[element.name] = true;
        validator.showErrors(errors);
        previous.valid = false;
        validator.stopRequest(element, false);
      } else {
        console.log('problem with validation server');
      }  
    }
  }, param));
  return "pending";
};

var myUrl = "https://api.zippopotam.us/us/";
//init jquery validation
$("#addressForm").validate({
  messages: {
    postalcode: 'Please enter a valid postal code'
  },
  rules: {
    postalcode: {
      required: true,
      remote: {
        url: myUrl,
        type: "get",
        data: ''
      }
    },
    city: {
      required: true,
    }
  }
});

$('input[name=postalcode]').on('change', function() {
  $('#success').hide();
  $('input[name=postalcode]').valid() 
})

$('#submit').on('click', function() {
  if ($("#addressForm").valid()) {
    $('#success').show();
  } else {
    $('#success').hide();
  }
})

【讨论】:

  • 您的答案的第二部分(您谈论编辑remote)不会对使用远程的每条规则都这样做吗?因为我也需要使用远程进行验证码。
  • 是的,在这种情况下,只需将自定义版本称为“remotePostal”之类的不同名称
猜你喜欢
  • 1970-01-01
  • 2015-01-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-14
  • 2013-04-05
  • 2021-12-24
相关资源
最近更新 更多