jQuery验证邮政编码填充城市

时间:2017-03-15 14:11:04

标签: jquery validation

我使用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调用,但是它并没有验证&#39;邮政编码领域。它只验证我的地址,验证码和城市字段(由代码完成)。

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

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

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

1 个答案:

答案 0 :(得分: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响应将返回&#34; true&#34;如果数据有效。你需要能够修改你的后端,以便有效的&#34;有效的&#34;如果邮政编码有效,将返回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();
  }
})