Angular 表单验证类库 ngx-validator 1.0 正式发布

背景介绍

之前写了一篇 《如何优雅的使用 Angular 表单验证》,结尾处介绍了统一验证反馈的类库 ngx-validator ,由于这段时间一直在新模块做微前端以及相关业务组件库,工具等开发,一直拖到现在,目前正式版 1.0 终于可以发布了。 可能有些人没有阅读过那篇博客,我这里简单介绍下 ngx-validator 主要的功能。

  1. 统一验证规则和错误反馈策略,通过响应式(配置的方式)设置每个元素对应每个验证器的错误提示文案以及统一错误信息反馈,避免手动写重复的模版实现错误提示,让开发人员专心写业务即可;
  2. 扩展一些 Angular 本身没有提供验证器和模版驱动的验证指令,比如 ngxUniqueCheckngxMaxngxMin;
  3. 支持模版驱动和响应式驱动表单的验证。

从上次 0.0.1 版本到 1.0.0 正式发布新增了的功能有:

  1. 新增了 validateOn 支持 submitblur 光标移走验证,之前只有点击按钮提交才会验证
  2. 对响应式表单支持的完善;
  3. 测试和 Demo 的完善;
  4. 重构了代码,添加了自动生成 changelog 和 husky 钩子做 commit message 规范检查和自动格式化(这些和库的功能无关,与开发者有关)

使用方式

如果你不想听我废话,可以直接看 示例 ,其中包括模版驱动和响应式驱动表单实现验证的全部代码。

安装

在你的项目中执行命令 npm install @why520crazy/ngx-validator --save 进行模块的安装

引入模块

在启动模块 AppModule 中直接引入 NgxValidatorModule,当然引入的时候可以通过 NgxValidatorModule.forRoot 进行一些全局参数的配置,配置包含全局的验证错误信息,错误反馈方式,目前反馈方式支持 boostrap4 的表单错误样式和 noop(什么都不提示),当然你可以扩展自己的错误反馈策略。

import { NgxValidatorModule, ValidationFeedbackStrategyBuilder } from '@why520crazy/ngx-validator';

@NgModule({
  imports: [
    CommonModule,
    NgxValidatorModule.forRoot({
         validationFeedbackStrategy: ValidationFeedbackStrategyBuilder.bootstrap(),
        validationMessages: {
            username: {
                required: 'Username is required.',
                pattern: 'Incorrect username format.'
            }
        }
    })
  ]
})
class AppModule {}
复制代码
模版驱动表单验证

在 form 表单元素上添加 ngxFormValidator 指令,配置的参数和全局配置的参数类似,此处单独配置只会对当前 Form 有效。 由于 ngxFormValidator 采用的验证器,以及元素是否验证通过完全读取的是 Angular 表单提供的信息,所以模版驱动表单必须遵循 Angular 表单的一些规则:

  1. 表单元素必须设置一个 name,这个 name 会和 ngForm controls 中的对象对应;
  2. 表单元素必须设置 ngModel,当提交表单时通过 ngModel 这只的变量获取用户输入的数据;
  3. 验证器直接设置到表单元素上,比如 Angular 内置的 requiredemailpatternmaxlengthminlength 以及 ngx-validator 类库提供的 ngxMaxngxMinngxUniqueCheck

最后在提交按钮上绑定 ngxFormSubmit 事件,当按钮点击后会触发表单验证,验证不通过会根据每个表单元素配置的提示信息反馈错误,如果使用的默认的 bootstrap4 的反馈策略,会在表单元素上加 is-invalid class 样式,同时在表单元素后追加 <div class="invalid-feedback">{相关的错误提示信息}</div>

 <form name="exampleForm" [ngxFormValidator]="validatorConfig">
   <div class="form-group">
       <label for="email1">Email address</label>
        <input type="email" email class="form-control" name="email" id="email1"
                [(ngModel)]="model.email" required placeholder="Enter email" />
    </div>
    <button type="button" (ngxFormSubmit)="submit()" class="btn btn-primary">Submit</button>
 <form>
复制代码

响应式驱动表单验证

响应式表单验证和模版驱动类似,区别就是不需要给每个元素加 ngModel 和 验证器,直接使用 formControlName 指令指定名称, 然后在组件中通过 FormBuilder 生成 group 即可,基本没有特殊配置,参考 Angular 官网的响应式表单验证示例即可。

APIs

ngxFormValidator 表单配置
属性名类型备注
validationMessages{[controlName: string]: {[validatorErrorKey: string]: string}}表单元素验证规则
validationFeedbackStrategyIValidationFeedbackStrategy没有配置,以全局配置的验证反馈策略为主
validateOn'submit' | 'blur'没有配置,以全局配置的 validateOn 为主
validatorConfig: NgxValidatorConfig = {
    validationMessages: {
        username: {
            required: '用户名不能为空',
            pattern: '用户名格式不正确,以字母,数字,下划线组成,首字母不能为数字,必须是2-20个字符',
            ngxUniqueCheck: '输入的用户名已经存在,请重新输入'
        }
    },
    validateOn: 'submit'
};
复制代码
全局配置

全局配置可以通过引入 NgxValidatorModule.forRoot(config) 进行设置,也可以在运行时注入 NgxValidatorLoader 服务进行配置

属性名类型备注
validationMessages{[controlName: string]: {[validatorErrorKey: string]: string}}表单元素验证规则
validationFeedbackStrategyIValidationFeedbackStrategy默认以 bootstrap 4 的表单错误提示展示
globalValidationMessages{[validatorErrorKey: string]: string}每个验证器全局的默认验证规则
validateOn'submit' | 'blur'触发验证,是提交触发验证还是光标移走触发验证

globalValidationMessages 默认规则如下,当某个表单元素比如 username 在表单和全局的 validationMessages 都没有被设置,验证不通过会直接显示 globalValidationMessages 中的 required 提示信息

{
    required: '该选项不能为空',
    maxlength: '该选项输入值长度不能大于{requiredLength}',
    minlength: '该选项输入值长度不能小于{requiredLength}',
    ngxUniqueCheck: '输入值已经存在,请重新输入',
    email: '输入邮件的格式不正确',
    repeat: '两次输入不一致',
    pattern: '该选项输入格式不正确',
    number: '必须输入数字',
    url: '输入URL格式不正确',
    max: '该选项输入值不能大于{max}',
    min: '该选项输入值不能小于{min}'
};
复制代码
扩展方法
  1. 单独验证某一个表单元素, 获取到 NgxFormValidatorDirective 实例 ngxFormValidator: NgxFormValidatorDirective,通过调用 ngxFormValidator.validator.validateControl(name: string) 方法单独验证;
  2. 根据服务端返回的错误,设置某个表单元素错误提示信息,调用 ngxFormValidator.validator.markControlAsError(name: string, errorMessage: string)
自定义反馈策略

如果你的项目不是使用 bootstrap4,而是其他 UI 库,那么可以通过扩展自己的错误反馈策略,然后在全局设置中配置一次后所有的表单验证都会使用配置之后的策略,以下是一个自定义反馈策略的示例:

const CUSTOM_INVALID_CLASS = 'custom-invalid';
const CUSTOM_INVALID_FEEDBACK_CLASS = 'custom-invalid-feedback';

export class CustomValidationFeedbackStrategy implements IValidationFeedbackStrategy {
    showError(element: HTMLElement, errorMessages: string[]): void {
        element.classList.add(CUSTOM_INVALID_CLASS);
        // add element show error message
    }

    removeError(element: HTMLElement): void {
        element.classList.remove(CUSTOM_INVALID_CLASS);
       // remove element error message
    }
}
复制代码

原文地址:zhuanlan.zhihu.com/p/65972116

转载于:https://juejin.im/post/5cdd0a486fb9a032514bd2d5

package com.lsm.util; import java.text.CharacterIterator; import java.text.StringCharacterIterator; /** * 用于校验一个字符串是否是合法的JSON格式 * @author liShuMin * */ public class JsonValidator { private CharacterIterator it; private char c; private int col; public JsonValidator(){ } /** * 验证一个字符串是否是合法的JSON串 * * @param input 要验证的字符串 * @return true-合法 ,false-非法 */ public boolean validate(String input) { input = input.trim(); boolean ret = valid(input); return ret; } private boolean valid(String input) { if ("".equals(input)) return true; boolean ret = true; it = new StringCharacterIterator(input); c = it.first(); col = 1; if (!value()) { ret = error("value", 1); } else { skipWhiteSpace(); if (c != CharacterIterator.DONE) { ret = error("end", col); } } return ret; } private boolean value() { return literal("true") || literal("false") || literal("null") || string() || number() || object() || array(); } private boolean literal(String text) { CharacterIterator ci = new StringCharacterIterator(text); char t = ci.first(); if (c != t) return false; int start = col; boolean ret = true; for (t = ci.next(); t != CharacterIterator.DONE; t = ci.next()) { if (t != nextCharacter()) { ret = false; break; } } nextCharacter(); if (!ret) error("literal " + text, start); return ret; } private boolean array() { return aggregate('[', ']', false); } private boolean object() { return aggregate('{', '}', true); } private boolean aggregate(char entryCharacter, char exitCharacter, boolean prefix) { if (c != entryCharacter) return false; nextCharacter(); skipWhiteSpace(); if (c == exitCharacter) { nextCharacter(); return true; } for (;;) { if (prefix) { int start = col; if (!string()) return error("string", start); skipWhiteSpace(); if (c != ':') return error("colon", col); nextCharacter(); skipWhiteSpace(); } if (value()) { skipWhiteSpace(); if (c == ',') { nextCharacter(); } else if (c == exitCharacter) { break; } else { return error("comma or " + exitCharacter, col); } } else { return error("value", col); } skipWhiteSpace(); } nextCharacter(); return true; } private boolean number() { if (!Character.isDigit(c) && c != '-') return false; int start = col; if (c == '-') nextCharacter(); if (c == '0') { nextCharacter(); } else if (Character.isDigit(c)) { while (Character.isDigit(c)) nextCharacter(); } else { return error("number", start); } if (c == '.') { nextCharacter(); if (Character.isDigit(c)) { while (Character.isDigit(c)) nextCharacter(); } else { return error("number", start); } } if (c == 'e' || c == 'E') { nextCharacter(); if (c == '+' || c == '-') { nextCharacter(); } if (Character.isDigit(c)) { while (Character.isDigit(c)) nextCharacter(); } else { return error("number", start); } } return true; } private boolean string() { if (c != '"') return false; int start = col; boolean escaped = false; for (nextCharacter(); c != CharacterIterator.DONE; nextCharacter()) { if (!escaped && c == '\\') { escaped = true; } else if (escaped) { if (!escape()) { return false; } escaped = false; } else if (c == '"') { nextCharacter(); return true; } } return error("quoted string", start); } private boolean escape() { int start = col - 1; if (" \\\"/bfnrtu".indexOf(c) < 0) { return error("escape sequence \\\",\\\\,\\/,\\b,\\f,\\n,\\r,\\t or \\uxxxx ", start); } if (c == 'u') { if (!ishex(nextCharacter()) || !ishex(nextCharacter()) || !ishex(nextCharacter()) || !ishex(nextCharacter())) { return error("unicode escape sequence \\uxxxx ", start); } } return true; } private boolean ishex(char d) { return "0123456789abcdefABCDEF".indexOf(c) >= 0; } private char nextCharacter() { c = it.next(); ++col; return c; } private void skipWhiteSpace() { while (Character.isWhitespace(c)) { nextCharacter(); } } private boolean error(String type, int col) { System.out.printf("type: %s, col: %s%s", type, col, System.getProperty("line.separator")); return false; } public static void main(String[] args){ //String jsonStr = "{\"website\":\"oschina.net\"}"; String jsonStr = "{" + " \"ccobjtypeid\": \"1001\"," + " \"fromuser\": \"李四\"," + " \"touser\": \"张三\"," + " \"desc\": \"描述\"," + " \"subject\": \"主题\"," + " \"attach\": \"3245,3456,4345,4553\"," + " \"data\": {" + " \"desc\": \"测试对象\"," + " \"dataid\": \"22\"," + " \"billno\": \"TEST0001\"," + " \"datarelation\":[" + " {" + " \"dataname\": \"关联对象1\"," + " \"data\": [" + " {" + " \"dataid\": \"22\"," + " \"datalineid\": \"1\"," + " \"content1\": \"test1\"," + " \"content2\": \"test2\"" + " }" + " ]" + " }" + " ]" + " }" + " }"; System.out.println(jsonStr+":"+new JsonValidator().validate(jsonStr)); } }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值