繁体   English   中英

如何使用第三方JS组件进行Angular2 / 4验证

[英]How to do Angular2/4 validation with 3rd party JS components

谈到Angular 2验证,我看到了不同的方法。 基本是使用HTML5和模板/模型绑定或具有指定验证器的表单。

然而,当涉及到特殊规则时,它需要大量编码和模板绑定(因此没有形式),这主要导致验证通过HTML和TS代码分散。

验证的另一个烦人的事情是你需要改变TS中的验证规则,并添加额外的HTML代码以在页面上呈现这些值(虽然这可以通过指令自动化)...

无论如何,理想的解决方案是使用规则来建模属性,然后向控件生成错误消息。 类似于.NET流畅验证和ModelState或类似于Aurelia.io验证的JS世界: http ://aurelia.io/docs/plugins/validation/

  1. Angular2 +中有类似的东西吗?
  2. 如何/在哪里检查(基于模型更改)到第三方(JS)库? 像fluent-ts-validator或flient-validator一样。
  3. 如何在控件上设置错误,尤其是当我们在内部有fe控件时
    控制...

我们需要的第一件事是将FormControls链接到输入元素。 它不是开箱即用的。 到目前为止唯一的解决方案(至少对于纯ngModel绑定)是我在这里发布的解决方案。

下面的代码不适用于纯ngModel绑定,所以我做了很多实验。 最新的,也由Maximillian Schwarzmuller证实应该是:

@Directive({
    selector: '[ngModel]', // or 'input, select, textarea' - but then your controls won't be handled and also checking for undefined would be necessary
})
export class NativeElementInjectorDirective {
    constructor(private el: ElementRef, private control : NgControl) {
        (<any>control.control).nativeElement = el.nativeElement;
    }
}

因此,如果在主模块中提供并导出此伪指令, 它将为所有FormControl附加自定义nativeElement属性

接下来要知道如何正确构建嵌套表单 - 请在此处查看链接

而且不仅仅是转发ngForm而且还转发ngModelGroup

@Component({
    selector: 'TestAddress',
    templateUrl: './address.location.html',
    viewProviders: [
        { provide: ControlContainer, useExisting: NgForm },
        { provide: ControlContainer, useExisting: forwardRef(() => NgModelGroup) },
    ],
    providers: [ MakeProvider(TestAddress) ]
})
export class TestProspectAddressLocation extends AbstractValueAccessor<any> {
...
}

我们不得不使用AbstractValueAccessor ,因此也使用MakeProvider。 这是链接

最后一篇:访问这些FormControls的方法:

this.form.get('HomeAddress.City').nativeElement

现在您可以订阅formValueChange和用户第三方进行验证,通过路径表达式访问任何控件,使用control.setErrors([])或只是通过jQuery aft附加HTML。 输入。

仍在寻找:

  1. 创建一些指令,可以将[(ngModel)]绑定添加到每个具有ngModel属性和名称定义的控件 - 而指定的表达式应该是'value'。 +名称属性值
  2. 一种用角度组件动态替换jQuery添加的div的方法 - 由于div是动态的,所以不能使用@ViewChild(selector)
  3. 使用带有[(ngModel)]绑定的嵌套表单会产生一个奇怪的FormGroup结构,因此自定义角度组件应该自动定义ngModelGroup ='name attr。 值'或使用ngControlOptions独立或其他方式应该是foud,这不会搞砸......

所以上面列表中的#2可以做到。

我们使用ngModel选择器来获取ref。 对于所有输入,当然我们有一个主控件(其中包含与验证相关的消息/代码),因此我们忽略不在该容器内的控件。

现在有了诀窍:我们确实为输入本身提供了一个viewContainerRef。 这允许我们在输入后立即注入控件。 由于注入是给定的viewContainer,当输入get被隐藏时,注入的控件被销毁...

编码:

import {Directive, OnInit, Optional, ViewContainerRef} from "@angular/core";
import {NgControl} from "@angular/forms";
import {ValidationContainerDirective} from "./validation-container-directive";

/*
This directive should match all inputs (ngModel)...
If it's inside a validation container, it'll process it...
 */
@Directive({
    selector: '[ngModel]'
})
export class ValidationControlForInjectorDirective implements OnInit {

    private initialized: boolean = false;

    constructor(@Optional() private validationContainer: ValidationContainerDirective,
                private control: NgControl,
                private viewContainerRef: ViewContainerRef,
              ) {

        // skip if not inside a validation container...
        if (!this.validationContainer)
            return;

        // mark as initialized
        this.initialized = true;
    }

    ngOnInit(): void {

        // skip if not initialized
        if (!this.initialized)
            return;

        var thisLocator = this.control.path.join(".");

        // check inputs...
        if (!thisLocator)
            throw new Error('Validation wire issues!');

        // add a control aft. the input...but disable it temporarily...
        this.validationContainer.injectComponent(this.viewContainerRef, thisLocator);
    }

}

上面的injectComponent方法只是设置我的控件并将其附加到viewContainerRef:

injectComponent(componentVcRef: ViewContainerRef, locator: string) {

    // create component
    var componentRef = componentVcRef.createComponent(this.componentFactoryForValidationControlFor);

    // basic set up (switching server/client messages on/off is done by the doCheckManagedComponents() fnc.
    (<ValidationControlFor>componentRef.instance).locator = locator;
    (<ValidationControlFor>componentRef.instance).isDynamic = true;
    (<ValidationControlFor>componentRef.instance).serverMessages = false;
    (<ValidationControlFor>componentRef.instance).clientMessages = false;
    (<ValidationControlFor>componentRef.instance).clientMessagesAlwaysVisible = this.clientMessagesAlwaysVisible;

    componentRef.changeDetectorRef.detectChanges();

    // NOTE:
    // registering of managed component is done via the component's ngOnInit function...
    // ...it was moved there, because we need to keep track also of manually added validation-message-controls!
}

您可以尝试一个名为ts.validator.fluent的框架/库。 通用对象验证。 流利的规则。

https://github.com/VeritasSoftware/ts.validator

此外,还有一个用于演示框架的Angular 6 CLI应用程序

https://github.com/VeritasSoftware/ts-validator-app-angular6

该应用程序使用面向服务的方法进行客户端表单验证 ,具有以下优势:

  • 围绕验证的业务规则与组件分开。
  • 业务规则集中在验证服务中。
  • 该服务可重复使用。
  • 该服务可以注入任何组件。
  • 您可以通过单元测试服务来对业务规则进行单元测试。

NPM套餐

https://www.npmjs.com/package/ts.validator.fluent

以下是如何使用框架验证TypeScript模型的示例:

/* Install npm package ts.validator.fluent and then import like below */
import { IValidator, Validator, ValidationResult } from 'ts.validator.fluent/dist';

/*TypeScript model*/
class Person {
   Name: string;
}

/* Validation rules */
var validatePersonRules = (validator: IValidator<Person>) : ValidationResult => {
  return validator
             .NotEmpty(m => m.Name, "Name cannot be empty")
        .ToResult();
};

/* Populate model */
var person = new Person();
person.Name = "Shane";

/* Validate model */
/* Sync */
var validationResult = new Validator(person).Validate(validatePersonRules); 
/* Async */
var validationResult = await new Validator(person).ValidateAsync(validatePersonRules);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM