代码之家  ›  专栏  ›  技术社区  ›  Francesco Borzi

如何创建一个自定义表单验证器来只接受Angular格式的有效JSON

  •  0
  • Francesco Borzi  · 技术社区  · 7 年前

    在我的 Angular configJson 它由一个 <textarea> 在国内。

    我需要验证此表单控件,使其仅接受来自用户输入的有效JSON文本,否则将显示错误消息。

    import { Component, OnInit } from '@angular/core';
    import { FormControl, FormGroup } from '@angular/forms';
    
    @Component({
      selector: 'app-configuration',
      templateUrl: './configuration.component.html',
      styleUrls: ['./configuration.component.scss']
    })
    export class ConfigurationComponent implements OnInit {
    
      form: FormGroup;
    
      constructor() {}
    
      ngOnInit() {
        this.form = new FormGroup({
          'configJson': new FormControl(),
        });
    
        // TODO: someone add JSON validation
      }
    
      loadJsonConfiguration() {
        const config = JSON.parse(this.form.get('configJson').value);
    
        // some logic here using the parsed "config" object...
      }
    }
    
    <form [formGroup]="form">
      <div class="form-group">
        <label for="json-config-textarea">Parse from JSON:</label>
        <textarea
          class="form-control"
          id="json-config-textarea"
          rows="10"
          [formControlName]="'configJson'"
        ></textarea>
      </div>
      <div [hidden]="form.get('configJson').pristine || form.get('configJson').valid">
        Please insert a valid JSON.
      </div>
      <div class="form-group text-right">
        <button
          class="btn btn-primary"
          (click)="loadJsonConfiguration()"
          [disabled]="form.get('configJson').pristine || form.get('configJson').invalid"
        >Load JSON Configuration</button>
      </div>
    </form>
    
    1 回复  |  直到 7 年前
        1
  •  4
  •   Daniel Smith    7 年前

    我最初试图编辑OP的答案,但被同行评论员拒绝,原因是:

    这篇文章的目的是针对文章的作者,而不是 感觉就像编辑一样。它应该写为评论或

    所以,这是我的修改版本:

    import {AbstractControl, ValidationErrors, ValidatorFn} from '@angular/forms';
    
    export function jsonValidator(control: AbstractControl): ValidationErrors | null {
      try {
        JSON.parse(control.value);
      } catch (e) {
        return { jsonInvalid: true };
      }
    
      return null;
    };
    
    import { Component, OnInit } from '@angular/core';
    import { FormControl, FormGroup, Validators } from '@angular/forms';
    
    import { jsonValidator } from './json.validator';
    
    @Component({
      selector: 'app-configuration',
      templateUrl: './configuration.component.html',
      styleUrls: ['./configuration.component.scss']
    })
    export class ConfigurationComponent implements OnInit {
    
      form: FormGroup;
    
      ngOnInit() {
        this.form = new FormGroup({
          configJson: new FormControl(Validators.compose(Validators.required, jsonValidator))
        });
      }
    
      loadJsonConfiguration() {
        ...
      }
    }
    
        2
  •  3
  •   Francesco Borzi    7 年前

    custom form validator 并将其附加到窗体控件。验证器的任务是只接受有效的 JSON .

    我的验证器是这样的:

    import {AbstractControl, ValidationErrors, ValidatorFn} from '@angular/forms';
    
    export function jsonValidator(): ValidatorFn {
      return (control: AbstractControl): ValidationErrors | null => {
        const error: ValidationErrors = { jsonInvalid: true };
    
        try {
          JSON.parse(control.value);
        } catch (e) {
          control.setErrors(error);
          return error;
        }
    
        control.setErrors(null);
        return null;
      };
    }
    

    可以通过以下方式轻松进行单元测试:

    import { FormControl, ValidationErrors, ValidatorFn } from '@angular/forms';
    import Spy = jasmine.Spy;
    
    import { jsonValidator } from './json.validator';
    
    describe('JSON Validator', () => {
      let control: FormControl;
      let spySetErrors: Spy;
      let validator: ValidatorFn;
    
      const errorName = 'jsonInvalid';
    
      beforeEach(() => {
        control = new FormControl(null);
        validator = jsonValidator();
        spySetErrors = spyOn(control, 'setErrors').and.callThrough();
      });
    
    
      for (const { testId, valid, value } of [
    
        { testId: 1, valid: true, value: '{}' },
        { testId: 2, valid: true, value: '{"myKey": "myValue"}' },
        { testId: 3, valid: true, value: '{"myKey1": "myValue1", "myKey2": "myValue2"}' },
        // more valid cases can be added...
    
        { testId: 4, valid: false, value: 'this is not a valid json' },
        { testId: 5, valid: false, value: '{"theJsonFormat": "doesntLikePendingCommas",}' },
        { testId: 6, valid: false, value: '{"theJsonFormat": doesntLikeMissingQuotes }' },
        // more invalid cases ca be added...
    
      ]) {
        it(`should only trigger the error when the control's value is not a valid JSON [${testId}]`, () => {
          const error: ValidationErrors = { [errorName]: true };
          control.setValue(value);
    
          if (valid) {
            expect(validator(control)).toBeNull();
            expect(control.getError(errorName)).toBeFalsy();
          } else {
            expect(validator(control)).toEqual(error);
            expect(control.getError(errorName)).toBe(true);
          }
        });
      }
    });
    

    在组件的 ngOnInit ,应添加新的验证器:

        this.form.get('configJson').setValidators([
          Validators.required, // this makes the field mandatory
          jsonValidator(), // this forces the user to insert valid json
        ]);
    

    import { Component, OnInit } from '@angular/core';
    import { FormControl, FormGroup, Validators } from '@angular/forms';
    
    import { jsonValidator } from './json.validator';
    
    @Component({
      selector: 'app-configuration',
      templateUrl: './configuration.component.html',
      styleUrls: ['./configuration.component.scss']
    })
    export class ConfigurationComponent implements OnInit {
    
      form: FormGroup;
    
      constructor() {}
    
      ngOnInit() {
        this.form = new FormGroup({
          'configJson': new FormControl(),
        });
    
        this.form.get('configJson').setValidators([
          Validators.required,
          jsonValidator(),
        ]);
      }
    
      loadJsonConfiguration() {
        const config = JSON.parse(this.form.get('configJson').value);
    
        // some logic here using the parsed "config" object...
      }
    }
    
    推荐文章