在我的Angular应用中,我有一个反应形式,为简单起见,我假设只有一个控件称为configJson
,该控件在DOM中由<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>
答案 0 :(得分:2)
一种解决方案是创建一个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...
}
}
答案 1 :(得分:0)
我最初尝试由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() {
...
}
}