#726 dropdown and typeahead validation

fixes #743
This commit is contained in:
Denys Vuika
2016-09-14 18:01:53 +01:00
parent 1adc87bc67
commit e99b48a6da
10 changed files with 96 additions and 27 deletions

View File

@@ -30,7 +30,9 @@ export class RequiredFieldValidator implements FormFieldValidator {
private supportedTypes = [
FormFieldTypes.TEXT,
FormFieldTypes.MULTILINE_TEXT,
FormFieldTypes.NUMBER
FormFieldTypes.NUMBER,
FormFieldTypes.TYPEAHEAD,
FormFieldTypes.DROPDOWN
];
isSupported(field: FormFieldModel): boolean {
@@ -41,6 +43,15 @@ export class RequiredFieldValidator implements FormFieldValidator {
validate(field: FormFieldModel): boolean {
if (this.isSupported(field)) {
if (field.type === FormFieldTypes.DROPDOWN) {
if (field.hasEmptyValue && field.emptyOption) {
if (field.value === field.emptyOption.id) {
return false;
}
}
}
if (!field.value) {
return false;
}

View File

@@ -66,6 +66,7 @@ export class FormFieldModel extends FormWidgetModel {
isVisible: boolean = true;
visibilityCondition: WidgetVisibilityModel = null;
emptyOption: FormFieldOption;
validationSummary: string;
validators: FormFieldValidator[] = [];
@@ -137,9 +138,11 @@ export class FormFieldModel extends FormWidgetModel {
this.hyperlinkUrl = json.hyperlinkUrl;
this.displayText = json.displayText;
this.visibilityCondition = <WidgetVisibilityModel> json.visibilityCondition;
this._value = this.parseValue(json);
this.updateForm();
}
if (this.hasEmptyValue && this.options && this.options.length > 0) {
this.emptyOption = this.options[0];
}
this.validators = [
@@ -151,6 +154,8 @@ export class FormFieldModel extends FormWidgetModel {
new MaxValueFieldValidator(),
new RegExFieldValidator()
];
this.updateForm();
}
parseValue(json: any): any {
@@ -160,10 +165,15 @@ export class FormFieldModel extends FormWidgetModel {
This is needed due to Activiti issue related to reading dropdown values as value string
but saving back as object: { id: <id>, name: <name> }
*/
// TODO: needs review
if (json.type === FormFieldTypes.DROPDOWN) {
if (value === '') {
value = 'empty';
if (json.hasEmptyValue && json.options) {
let options = <FormFieldOption[]> json.options || [];
if (options.length > 0) {
let emptyOption = json.options[0];
if (value === '' || value === emptyOption.id || value === emptyOption.name) {
value = emptyOption.id;
}
}
}
}

View File

@@ -2,6 +2,22 @@
width: 100%;
}
.dropdown-widget > select {
.dropdown-widget__select {
width: 100%;
}
.dropdown-widget__invalid .dropdown-widget__select {
border-color: #d50000;
}
.dropdown-widget__invalid .dropdown-widget__label {
color: #d50000;
}
.dropdown-widget__invalid .dropdown-widget__label:after {
background-color: #d50000;
}
.dropdown-widget__invalid .mdl-textfield__error {
visibility: visible !important;
}

View File

@@ -1,6 +1,10 @@
<div class="dropdown-widget">
<label [attr.for]="field.id">{{field.name}}</label>
<select [(ngModel)]="field.value" (ngModelChange)="checkVisibility(field)">
<div class="dropdown-widget"
[class.dropdown-widget__invalid]="!field.isValid">
<label class="dropdown-widget__label" [attr.for]="field.id">{{field.name}}</label>
<select class="dropdown-widget__select"
[(ngModel)]="field.value"
(ngModelChange)="checkVisibility(field)">
<option *ngFor="let opt of field.options" [value]="opt.id">{{opt.name}}</option>
</select>
<span *ngIf="field.validationSummary" class="mdl-textfield__error">{{field.validationSummary}}</span>
</div>

View File

@@ -42,7 +42,8 @@ describe('DropdownWidget', () => {
});
widget.field = new FormFieldModel(form, {
id: fieldId
id: fieldId,
restUrl: '<url>'
});
spyOn(formService, 'getRestFieldValues').and.returnValue(Observable.create(observer => {

View File

@@ -36,18 +36,24 @@ export class DropdownWidget extends WidgetComponent implements OnInit {
}
ngOnInit() {
this.formService
.getRestFieldValues(
this.field.form.taskId,
this.field.id
)
.subscribe(
(result: FormFieldOption[]) => {
this.field.options = result || [];
this.field.updateForm();
},
this.handleError
);
if (this.field && this.field.restUrl) {
this.formService
.getRestFieldValues(
this.field.form.taskId,
this.field.id
)
.subscribe(
(result: FormFieldOption[]) => {
let options = [];
if (this.field.emptyOption) {
options.push(this.field.emptyOption);
}
this.field.options = options.concat((result || []));
this.field.updateForm();
},
this.handleError
);
}
}
handleError(error: any) {

View File

@@ -9,6 +9,5 @@
(ngModelChange)="checkVisibility(field)"
[disabled]="field.readOnly">
<label class="mdl-textfield__label" [attr.for]="field.id">{{field.name}}</label>
<!--<span class="mdl-textfield__error">Input is not a number!</span>-->
<span *ngIf="field.validationSummary" class="mdl-textfield__error">{{field.validationSummary}}</span>
</div>

View File

@@ -27,3 +27,21 @@
.typeahead-autocomplete > ul > li {
opacity: 1;
}
.typeahead-widget__invalid .mdl-textfield__input {
border-color: #d50000;
}
.typeahead-widget__invalid .mdl-textfield__label {
color: #d50000;
}
.typeahead-widget__invalid .mdl-textfield__label:after {
background-color: #d50000;
}
.typeahead-widget__invalid .mdl-textfield__error {
visibility: visible !important;
}

View File

@@ -1,5 +1,6 @@
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label typeahead-widget"
[class.is-dirty]="value">
[class.is-dirty]="value"
[class.typeahead-widget__invalid]="!field.isValid">
<input class="mdl-textfield__input"
type="text"
[attr.id]="field.id"
@@ -9,8 +10,8 @@
(blur)="onBlur()"
[disabled]="field.readOnly">
<label class="mdl-textfield__label" [attr.for]="field.id">{{field.name}}</label>
<span *ngIf="field.validationSummary" class="mdl-textfield__error">{{field.validationSummary}}</span>
</div>
<div class="typeahead-autocomplete mdl-shadow--2dp" *ngIf="options.length > 0 && popupVisible">
<ul>
<li *ngFor="let item of options"

View File

@@ -91,7 +91,9 @@ export class TypeaheadWidget extends WidgetComponent implements OnInit {
this.popupVisible = false;
let options = this.field.options || [];
let field = options.find(item => item.name.toLocaleLowerCase() === this.value.toLocaleLowerCase());
let lValue = this.value ? this.value.toLocaleLowerCase() : null;
let field = options.find(item => item.name && item.name.toLocaleLowerCase() === lValue);
if (field) {
this.field.value = field.id;
this.value = field.name;
@@ -100,6 +102,7 @@ export class TypeaheadWidget extends WidgetComponent implements OnInit {
this.value = null;
}
// TODO: seems to be not needed as field.value setter calls it
this.field.updateForm();
}