Как создать специальный валидатор форм для принятия только допустимого JSON в Angular - PullRequest
0 голосов
/ 18 апреля 2019

В моем приложении Angular у меня есть реактивная форма, которая для простоты я предполагаю, что в DOM есть только один элемент управления, называемый 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>

Ответы [ 2 ]

2 голосов
/ 18 апреля 2019

Одним из решений является создание пользовательского валидатора форм и присоединение его к элементу управления формы.Работа валидатора заключается в том, чтобы принимать только действительные 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...
  }
}
1 голос
/ 19 апреля 2019

Первоначально я пытался отредактировать ответ от ОП, но он был отклонен рецензентами из-за:

Эта редакция была предназначена для обращения к автору поста и не делает никаких смысл как редактирование. Это должно было быть написано как комментарий или ответить.

Итак, вот моя модифицированная версия:

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() {
    ...
  }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...