专栏首页finleyMaAngular 表单3--响应式表单 复杂验证

Angular 表单3--响应式表单 复杂验证

表单验证是前端开发中重要的并且常见的工作 比如下面的表单包含三个字段:

  • 验证要求: name: 必填 Category: 必填,只能输入大小写,字符长度3到10 Price:必填,只能输入不超过100的数字
  • 显示要求: 错误在表单上放统一显示

image.png

我们可以借助Angular的formControl来实现,这里我们基于FormControl创建一个子类ProductFormControl来提高可复用性

核心代码: form.model.ts 该文件是表单模型文件,与业务无关。只包含一个收集表单错误信息的方法

import { FormControl, FormGroup, Validators } from "@angular/forms";
// 自定义验证器
import { LimitValidator } from "./limit.formvalidator";

export class ProductFormControl extends FormControl {
    label: string;
    modelProperty: string;

    constructor(label:string, property:string, value: any, validator: any) {
        super(value, validator);
        this.label = label;
        this.modelProperty = property;
    }
    // 此方法用于收集错误信息,然后在模板中遍历输出,
    getValidationMessages() {
        let messages: string[] = [];
        if (this.errors) {
            for (let errorName in this.errors) {
                switch (errorName) {
                    case "required":
                        messages.push(`You must enter a ${this.label}`);
                        break;
                    case "minlength":
                        messages.push(`A ${this.label} must be at least
                            ${this.errors['minlength'].requiredLength}
                            characters`);
                        break;
                    case "maxlength":
                        messages.push(`A ${this.label} must be no more than
                            ${this.errors['maxlength'].requiredLength}
                            characters`);
                        break;
                    case "limit":
                        messages.push(`A ${this.label} cannot be more
                                than ${this.errors['limit'].limit}`);
                        break;
                    case "pattern":
                        messages.push(`The ${this.label} contains
                             illegal characters`);
                        break;
                }
            }
        }
        return messages;
    }
}

// 业务相关,专门验证 Product Form
// 注意 new ProductFormControl() 不是 new FormControl()
export class ProductFormGroup extends FormGroup {

    constructor() {
        super({
            name: new ProductFormControl("Name", "name", "", Validators.required),
            category: new ProductFormControl("Category", "category", "",
                Validators.compose([Validators.required,
                    Validators.pattern("^[A-Za-z ]+$"),
                    Validators.minLength(3),
                    Validators.maxLength(10)])),
            price: new ProductFormControl("Price", "price", "",
                Validators.compose([Validators.required,
                    LimitValidator.Limit(100),
                    Validators.pattern("^[0-9\.]+$")]))
        });
    }

    get productControls(): ProductFormControl[] {
        return Object.keys(this.controls)
            .map(k => this.controls[k] as ProductFormControl);
    }

    getFormValidationMessages(form: any) : string[] {
        let messages: string[] = [];
        this.productControls.forEach(c => c.getValidationMessages()
            .forEach(m => messages.push(m)));
        return messages;
    }
}

其中 limit.formvalidator.ts 封装了一个验证长度限制的自定义验证器

import { FormControl } from "@angular/forms";

export class LimitValidator {

    static Limit(limit:number) {
        return (control:FormControl) : {[key: string]: any} => {
            let val = Number(control.value);
            if (val != NaN && val > limit) {
                return {"limit": {"limit": limit, "actualValue": val}};
            } else {
                return null;
            }
        }
    }
}

最后在用到的组件中,直接引入 form.model

import { Component } from "@angular/core";
import { NgForm } from "@angular/forms";
import { Product } from "./product.model";
import { ProductFormGroup } from "./form.model";

@Component({
    selector: "app",
    templateUrl: "template.html"
})
export class ProductComponent {
    form: ProductFormGroup = new ProductFormGroup();

    newProduct: Product = new Product();

    get jsonProduct() {
        return JSON.stringify(this.newProduct);
    }

    addProduct(p: Product) {
        console.log("New Product: " + this.jsonProduct);
    }

    formSubmitted: boolean = false;

    submitForm(form: NgForm) {
        this.formSubmitted = true;
        if (form.valid) {
            this.addProduct(this.newProduct);
            this.newProduct = new Product();
            form.reset();
            this.formSubmitted = false;
        }
    }
}

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • RxJS 在 Angular响应式表单中的使用

    FormControl 的 valueChanges 属性和 statusChanges 属性包含了会发出变更事件的可观察对象。 例子

    mafeifan
  • Angular 表单2--响应式表单, 处理异步数据

    上一节中我们定义了一个响应式表单,其中表单数据是在定义的时候就初始化好的,但是很多时候数据需要异步获取,比如 打开一个编辑页面,需要

    mafeifan
  • Angular 表单1--响应式表单

    Angular 提供了两种不同的方法来通过表单处理用户输入:响应式表单和模板驱动表单。 本节先讲响应式表单。 最终实例demo app-component...

    mafeifan
  • Mybatis深入源码分析之SqlSessionFactoryBuilder源码分析

    通过上述代码可知:使用了门面模式:定义了Resource类,把复杂过程封装起来,方便用户使用,返回reader为InputStreamReader,指的是读取的...

    须臾之余
  • 数据结构与JS也可以成为CP(十)Graph图

    1)深度优先搜索算法比较简单:访问一个没有访问过的顶点,将它标记为已访问,再递归地去访问在初始顶点的邻接表中其他没有访问过的顶点。

    萌兔IT
  • 商品多种规格属性的选择(sku 算法)

    如上图中每一个单规格选项,例如==珍珠白==、==12GB+512GB==、==不分期==就是一个规格(sku)。商品和 sku 属于一对多的关系,也就是我们可...

    Krry
  • ASP.NET AJAX(14)__UpdatePanel与服务器端脚本控件脚本控件的作用脚本控件的指责Extender模型脚本控件和Extender模型在PostBack中保持状态在UpdatePa

    脚本控件的作用 ASP.NET AJAX的脚本控件,连接了服务器端和客户端,因为我们(可以)只在服务器端编程,而效果产生在客户端,这就需要我们首先在服务器端编写...

    小白哥哥
  • 左右滚动,带控制按钮

    今天需要一个左右滚动图的js,从网上着了半天,修改调试了半天才弄好,于是就收藏了。不过以后真得看看js了 关键代码有注释:(红色部分是我加的注释) <table...

    苦咖啡
  • Flutter开发:TextField常用属性的使用

    在flutter开发过程中,掌握常用组件的使用是必备技能,flutter常用的组件和App开发时候常用的控件基本一模一样,只是使用的方式不一样罢了。

    三掌柜
  • 移动端 局部dom实现滚动

    https://github.com/surmon-china/vue-awesome-swiper/issues/423

    念念不忘

扫码关注云+社区

领取腾讯云代金券