[ADF-1679] added translation for form field validators (#2455)

* [ADF-1679] added translation for form field validators

* [ADF-1679] fixed typeahead test
This commit is contained in:
Vito 2017-10-11 10:11:52 +01:00 committed by Denys Vuika
parent 2e0a6936aa
commit fcda2228fa
13 changed files with 110 additions and 50 deletions

View File

@ -26,7 +26,7 @@ export class DemoFieldValidator implements FormFieldValidator {
validate(field: FormFieldModel): boolean { validate(field: FormFieldModel): boolean {
if (this.isSupported(field)) { if (this.isSupported(field)) {
if (field.value && field.value.toLowerCase() === 'admin') { if (field.value && field.value.toLowerCase() === 'admin') {
field.validationSummary = 'Sorry, the value cannot be "admin".'; field.validationSummary.message = 'Sorry, the value cannot be "admin".';
return false; return false;
} }
} }

View File

@ -0,0 +1,45 @@
/*!
* @license
* Copyright 2016 Alfresco Software, Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* tslint:disable:component-selector */
export class ErrorMessageModel {
message: string = '';
attributes: Map<string, string> = null;
constructor(obj?: any) {
this.message = obj && obj.message ? obj.message : '';
this.attributes = new Map();
}
isActive() {
return this.message ? true : false;
}
getAttributesAsJsonObj() {
let result = {};
if (this.attributes.size > 0) {
let obj = Object.create(null);
this.attributes.forEach((value, key) => {
obj[key] = value;
});
result = JSON.stringify(obj);
}
return result;
}
}

View File

@ -15,6 +15,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { ErrorMessageModel } from './error-message.model';
import { FormFieldOption } from './form-field-option'; import { FormFieldOption } from './form-field-option';
import { FormFieldTypes } from './form-field-types'; import { FormFieldTypes } from './form-field-types';
import { import {
@ -229,7 +230,7 @@ describe('FormFieldValidator', () => {
value: '<value>' value: '<value>'
}); });
field.validationSummary = null; field.validationSummary = new ErrorMessageModel();
expect(validator.validate(field)).toBeFalsy(); expect(validator.validate(field)).toBeFalsy();
expect(field.validationSummary).not.toBeNull(); expect(field.validationSummary).not.toBeNull();
}); });
@ -282,7 +283,7 @@ describe('FormFieldValidator', () => {
value: '12' value: '12'
}); });
field.validationSummary = null; field.validationSummary = new ErrorMessageModel();
expect(validator.validate(field)).toBeFalsy(); expect(validator.validate(field)).toBeFalsy();
expect(field.validationSummary).not.toBeNull(); expect(field.validationSummary).not.toBeNull();
}); });
@ -335,7 +336,7 @@ describe('FormFieldValidator', () => {
value: '1234' value: '1234'
}); });
field.validationSummary = null; field.validationSummary = new ErrorMessageModel();
expect(validator.validate(field)).toBeFalsy(); expect(validator.validate(field)).toBeFalsy();
expect(field.validationSummary).not.toBeNull(); expect(field.validationSummary).not.toBeNull();
}); });
@ -406,7 +407,7 @@ describe('FormFieldValidator', () => {
minValue: '10' minValue: '10'
}); });
field.validationSummary = null; field.validationSummary = new ErrorMessageModel();
expect(validator.validate(field)).toBeFalsy(); expect(validator.validate(field)).toBeFalsy();
expect(field.validationSummary).not.toBeNull(); expect(field.validationSummary).not.toBeNull();
}); });
@ -478,7 +479,7 @@ describe('FormFieldValidator', () => {
maxValue: '10' maxValue: '10'
}); });
field.validationSummary = null; field.validationSummary = new ErrorMessageModel();
expect(validator.validate(field)).toBeFalsy(); expect(validator.validate(field)).toBeFalsy();
expect(field.validationSummary).not.toBeNull(); expect(field.validationSummary).not.toBeNull();
}); });

View File

@ -118,7 +118,7 @@ export class NumberFieldValidator implements FormFieldValidator {
if (valueStr.match(pattern)) { if (valueStr.match(pattern)) {
return true; return true;
} }
field.validationSummary = 'Incorrect number format'; field.validationSummary.message = 'FORM.FIELD.VALIDATOR.INVALID_NUMBER';
return false; return false;
} }
return true; return true;
@ -150,7 +150,7 @@ export class DateFieldValidator implements FormFieldValidator {
if (DateFieldValidator.isValidDate(field.value, field.dateDisplayFormat)) { if (DateFieldValidator.isValidDate(field.value, field.dateDisplayFormat)) {
return true; return true;
} }
field.validationSummary = field.dateDisplayFormat; field.validationSummary.message = field.dateDisplayFormat;
return false; return false;
} }
return true; return true;
@ -173,7 +173,7 @@ export class MinDateFieldValidator implements FormFieldValidator {
const dateFormat = field.dateDisplayFormat; const dateFormat = field.dateDisplayFormat;
if (!DateFieldValidator.isValidDate(field.value, dateFormat)) { if (!DateFieldValidator.isValidDate(field.value, dateFormat)) {
field.validationSummary = 'Invalid date format'; field.validationSummary.message = 'FORM.FIELD.VALIDATOR.INVALID_DATE';
return false; return false;
} }
@ -187,7 +187,8 @@ export class MinDateFieldValidator implements FormFieldValidator {
let min = moment(field.minValue, dateFormat); let min = moment(field.minValue, dateFormat);
if (d.isBefore(min)) { if (d.isBefore(min)) {
field.validationSummary = `Should not be less than ${field.minValue}`; field.validationSummary.message = `FORM.FIELD.VALIDATOR.NOT_LESS_THAN`;
field.validationSummary.attributes.set('minValue', field.minValue.toLocaleString());
return false; return false;
} }
} }
@ -211,7 +212,7 @@ export class MaxDateFieldValidator implements FormFieldValidator {
const dateFormat = field.dateDisplayFormat; const dateFormat = field.dateDisplayFormat;
if (!DateFieldValidator.isValidDate(field.value, dateFormat)) { if (!DateFieldValidator.isValidDate(field.value, dateFormat)) {
field.validationSummary = 'Invalid date format'; field.validationSummary.message = 'FORM.FIELD.VALIDATOR.INVALID_DATE';
return false; return false;
} }
@ -225,7 +226,8 @@ export class MaxDateFieldValidator implements FormFieldValidator {
let max = moment(field.maxValue, dateFormat); let max = moment(field.maxValue, dateFormat);
if (d.isAfter(max)) { if (d.isAfter(max)) {
field.validationSummary = `Should not be greater than ${field.maxValue}`; field.validationSummary.message = `FORM.FIELD.VALIDATOR.NOT_GREATER_THAN`;
field.validationSummary.attributes.set('maxValue', field.maxValue.toLocaleString());
return false; return false;
} }
} }
@ -251,7 +253,8 @@ export class MinLengthFieldValidator implements FormFieldValidator {
if (field.value.length >= field.minLength) { if (field.value.length >= field.minLength) {
return true; return true;
} }
field.validationSummary = `Should be at least ${field.minLength} characters long.`; field.validationSummary.message = `FORM.FIELD.VALIDATOR.AT_LEAST_LONG`;
field.validationSummary.attributes.set('minLength', field.minLength.toLocaleString());
return false; return false;
} }
return true; return true;
@ -276,7 +279,8 @@ export class MaxLengthFieldValidator implements FormFieldValidator {
if (field.value.length <= field.maxLength) { if (field.value.length <= field.maxLength) {
return true; return true;
} }
field.validationSummary = `Should be ${field.maxLength} characters maximum.`; field.validationSummary.message = `FORM.FIELD.VALIDATOR.NO_LONGER_THAN`;
field.validationSummary.attributes.set('maxLength', field.maxLength.toLocaleString());
return false; return false;
} }
return true; return true;
@ -304,7 +308,8 @@ export class MinValueFieldValidator implements FormFieldValidator {
if (value >= minValue) { if (value >= minValue) {
return true; return true;
} }
field.validationSummary = `Should not be less than ${field.minValue}`; field.validationSummary.message = `FORM.FIELD.VALIDATOR.NOT_LESS_THAN`;
field.validationSummary.attributes.set('minValue', field.minValue.toLocaleString());
return false; return false;
} }
@ -333,7 +338,8 @@ export class MaxValueFieldValidator implements FormFieldValidator {
if (value <= maxValue) { if (value <= maxValue) {
return true; return true;
} }
field.validationSummary = `Should not be greater than ${field.maxValue}`; field.validationSummary.message = `FORM.FIELD.VALIDATOR.NOT_GREATER_THAN`;
field.validationSummary.attributes.set('maxValue', field.maxValue.toLocaleString());
return false; return false;
} }
@ -358,7 +364,7 @@ export class RegExFieldValidator implements FormFieldValidator {
if (field.value.length > 0 && field.value.match(new RegExp('^' + field.regexPattern + '$'))) { if (field.value.length > 0 && field.value.match(new RegExp('^' + field.regexPattern + '$'))) {
return true; return true;
} }
field.validationSummary = 'Invalid value format'; field.validationSummary.message = 'FORM.FIELD.VALIDATOR.INVALID_VALUE';
return false; return false;
} }
return true; return true;
@ -399,7 +405,7 @@ export class FixedValueFieldValidator implements FormFieldValidator {
validate(field: FormFieldModel): boolean { validate(field: FormFieldModel): boolean {
if (this.isSupported(field)) { if (this.isSupported(field)) {
if (this.hasStringValue(field) && this.hasOptions(field) && !this.hasValidNameOrValidId(field)) { if (this.hasStringValue(field) && this.hasOptions(field) && !this.hasValidNameOrValidId(field)) {
field.validationSummary = 'Invalid data inserted'; field.validationSummary.message = 'FORM.FIELD.VALIDATOR.INVALID_VALUE';
return false; return false;
} }
} }

View File

@ -19,6 +19,7 @@
import * as moment from 'moment'; import * as moment from 'moment';
import { WidgetVisibilityModel } from '../../../models/widget-visibility.model'; import { WidgetVisibilityModel } from '../../../models/widget-visibility.model';
import { ContainerColumnModel } from './container-column.model'; import { ContainerColumnModel } from './container-column.model';
import { ErrorMessageModel } from './error-message.model';
import { FormFieldMetadata } from './form-field-metadata'; import { FormFieldMetadata } from './form-field-metadata';
import { FormFieldOption } from './form-field-option'; import { FormFieldOption } from './form-field-option';
import { FormFieldTypes } from './form-field-types'; import { FormFieldTypes } from './form-field-types';
@ -75,7 +76,7 @@ export class FormFieldModel extends FormWidgetModel {
// util members // util members
emptyOption: FormFieldOption; emptyOption: FormFieldOption;
validationSummary: string; validationSummary: ErrorMessageModel;
get value(): any { get value(): any {
return this._value; return this._value;
@ -117,7 +118,7 @@ export class FormFieldModel extends FormWidgetModel {
} }
validate(): boolean { validate(): boolean {
this.validationSummary = null; this.validationSummary = new ErrorMessageModel();
let validators = this.form.fieldValidators || []; let validators = this.form.fieldValidators || [];
for (let validator of validators) { for (let validator of validators) {
@ -165,6 +166,7 @@ export class FormFieldModel extends FormWidgetModel {
this.currency = json.currency; this.currency = json.currency;
this.dateDisplayFormat = json.dateDisplayFormat || this.defaultDateFormat; this.dateDisplayFormat = json.dateDisplayFormat || this.defaultDateFormat;
this._value = this.parseValue(json); this._value = this.parseValue(json);
this.validationSummary = new ErrorMessageModel();
if (json.placeholder && json.placeholder !== '' && json.placeholder !== 'null') { if (json.placeholder && json.placeholder !== '' && json.placeholder !== 'null') {
this.placeholder = json.placeholder; this.placeholder = json.placeholder;

View File

@ -32,3 +32,4 @@ export * from './form-outcome.model';
export * from './form-outcome-event.model'; export * from './form-outcome-event.model';
export * from './form-field-validator'; export * from './form-field-validator';
export * from './content-link.model'; export * from './content-link.model';
export * from './error-message.model';

View File

@ -1,4 +1,4 @@
<div class="{{field.className}}" *ngIf="field?.isVisible" id="data-widget" [class.adf-invalid]="!field.isValid || field.validationSummary"> <div class="{{field.className}}" *ngIf="field?.isVisible" id="data-widget" [class.adf-invalid]="!field.isValid || field.validationSummary.message">
<md-input-container class="adf-date-widget"> <md-input-container class="adf-date-widget">
<label class="adf-label" [attr.for]="field.id">{{field.name}} ({{field.dateDisplayFormat}})<span *ngIf="isRequired()">*</span></label> <label class="adf-label" [attr.for]="field.id">{{field.name}} ({{field.dateDisplayFormat}})<span *ngIf="isRequired()">*</span></label>
<input mdInput <input mdInput
@ -14,7 +14,7 @@
placeholder="{{field.placeholder}}"> placeholder="{{field.placeholder}}">
<md-datepicker-toggle mdSuffix [for]="datePicker" [disabled]="field.readOnly" ></md-datepicker-toggle> <md-datepicker-toggle mdSuffix [for]="datePicker" [disabled]="field.readOnly" ></md-datepicker-toggle>
</md-input-container> </md-input-container>
<error-widget [error]="field.validationSummary" ></error-widget> <error-widget [error]="field.validationSummary"></error-widget>
<error-widget *ngIf="isInvalidFieldRequired()" required="{{ 'FORM.FIELD.REQUIRED' | translate }}"></error-widget> <error-widget *ngIf="isInvalidFieldRequired()" required="{{ 'FORM.FIELD.REQUIRED' | translate }}"></error-widget>
<md-datepicker #datePicker [touchUi]="true" [startAt]="startAt" ></md-datepicker> <md-datepicker #datePicker [touchUi]="true" [startAt]="startAt" ></md-datepicker>
</div> </div>

View File

@ -59,24 +59,15 @@ export class DateWidgetComponent extends WidgetComponent implements OnInit {
this.maxDate = moment(this.field.maxValue, this.field.dateDisplayFormat); this.maxDate = moment(this.field.maxValue, this.field.dateDisplayFormat);
} }
} }
this.displayDate = moment(this.field.value, this.field.dateDisplayFormat); this.displayDate = moment(this.field.value, this.field.dateDisplayFormat);
} }
onDateChanged(newDateValue) { onDateChanged(newDateValue) {
this.field.validationSummary = ''; if (newDateValue && newDateValue.value) {
this.field.value = newDateValue.value.format(this.field.dateDisplayFormat);
if (newDateValue) { }else if ( newDateValue ) {
let momentDate = newDateValue.value; this.field.value = newDateValue;
if (!momentDate.isValid()) { }else {
this.field.validationSummary = this.field.dateDisplayFormat;
this.field.value = null;
} else {
this.field.value = momentDate;
this.displayDate = moment(this.field.value, this.field.dateDisplayFormat);
}
} else {
this.field.value = null; this.field.value = null;
} }
this.checkVisibility(this.field); this.checkVisibility(this.field);

View File

@ -1,6 +1,6 @@
<div class="adf-error-text-container"> <div class="adf-error-text-container">
<div *ngIf="error" [@transitionMessages]="_subscriptAnimationState"> <div *ngIf="error.isActive()" [@transitionMessages]="_subscriptAnimationState">
<div class="adf-error-text">{{error}}</div> <div class="adf-error-text">{{error.message | translate:translateParameters}}</div>
<i class="material-icons adf-error-icon">warning</i> <i class="material-icons adf-error-icon">warning</i>
</div> </div>
<div *ngIf="required" [@transitionMessages]="_subscriptAnimationState"> <div *ngIf="required" [@transitionMessages]="_subscriptAnimationState">

View File

@ -18,7 +18,8 @@
/* tslint:disable:component-selector */ /* tslint:disable:component-selector */
import { animate, state, style, transition, trigger } from '@angular/animations'; import { animate, state, style, transition, trigger } from '@angular/animations';
import { AfterViewInit, Component, Input, OnChanges, SimpleChanges, ViewEncapsulation } from '@angular/core'; import { Component, Input, OnChanges, SimpleChanges, ViewEncapsulation } from '@angular/core';
import { ErrorMessageModel } from '../core/index';
import { FormService } from './../../../services/form.service'; import { FormService } from './../../../services/form.service';
import { baseHost , WidgetComponent } from './../widget.component'; import { baseHost , WidgetComponent } from './../widget.component';
@ -38,29 +39,33 @@ import { baseHost , WidgetComponent } from './../widget.component';
host: baseHost, host: baseHost,
encapsulation: ViewEncapsulation.None encapsulation: ViewEncapsulation.None
}) })
export class ErrorWidgetComponent extends WidgetComponent implements AfterViewInit, OnChanges { export class ErrorWidgetComponent extends WidgetComponent implements OnChanges {
@Input() @Input()
error: string; error: ErrorMessageModel;
@Input() @Input()
required: string; required: string;
translateParameters: any = null;
_subscriptAnimationState: string = ''; _subscriptAnimationState: string = '';
constructor(public formService: FormService) { constructor(public formService: FormService) {
super(formService); super(formService);
} }
ngAfterViewInit() {
this._subscriptAnimationState = 'enter';
}
ngOnChanges(changes: SimpleChanges) { ngOnChanges(changes: SimpleChanges) {
if (changes['required']) { if (changes['required']) {
this.required = changes.required.currentValue; this.required = changes.required.currentValue;
this._subscriptAnimationState = 'enter'; this._subscriptAnimationState = 'enter';
} }
if (changes['error']) {
if (changes.error.currentValue.isActive()) {
this.error = changes.error.currentValue;
this.translateParameters = this.error.getAttributesAsJsonObj();
this._subscriptAnimationState = 'enter';
}
}
} }
} }

View File

@ -93,12 +93,12 @@ export class PeopleWidgetComponent extends WidgetComponent implements OnInit {
validateValue() { validateValue() {
let validUserName = this.getUserFromValue(); let validUserName = this.getUserFromValue();
if (validUserName) { if (validUserName) {
this.field.validationSummary = ''; this.field.validationSummary.message = '';
this.field.value = validUserName; this.field.value = validUserName;
this.value = this.getDisplayName(validUserName); this.value = this.getDisplayName(validUserName);
} else { } else {
this.field.value = ''; this.field.value = '';
this.field.validationSummary = 'Invalid value provided'; this.field.validationSummary.message = 'Invalid value provided';
this.field.markAsInvalid(); this.field.markAsInvalid();
this.field.form.markAsInvalid(); this.field.form.markAsInvalid();
} }

View File

@ -336,7 +336,7 @@ describe('TypeaheadWidgetComponent', () => {
fixture.whenStable().then(() => { fixture.whenStable().then(() => {
fixture.detectChanges(); fixture.detectChanges();
expect(element.querySelector('.adf-error-text')).not.toBeNull(); expect(element.querySelector('.adf-error-text')).not.toBeNull();
expect(element.querySelector('.adf-error-text').textContent).toContain('Invalid data inserted'); expect(element.querySelector('.adf-error-text').textContent).toContain('FORM.FIELD.VALIDATOR.INVALID_VALUE');
}); });
})); }));

View File

@ -7,7 +7,16 @@
"IMAGE_NOT_AVAILABLE": "Preview not available" "IMAGE_NOT_AVAILABLE": "Preview not available"
}, },
"FIELD": { "FIELD": {
"REQUIRED" : "*Required" "REQUIRED" : "*Required",
"VALIDATOR" : {
"INVALID_NUMBER" : "Incorrect number format",
"INVALID_DATE" : "Invalid date format",
"INVALID_VALUE": "Invalid value inserted",
"NOT_GREATER_THAN" : "Should not be greater than {{ maxValue }}",
"NOT_LESS_THAN" : "Should not be less than {{ minValue }}",
"AT_LEAST_LONG" : "Should be at least {{ minLength }} characters long.",
"NO_LONGER_THAN" : "Should be {{ maxLength }} characters maximum."
}
} }
} }
} }