mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-05-19 17:14:57 +00:00
Basic input validation (dynamic table)
This commit is contained in:
parent
3c0ad93477
commit
fe7b05df4f
@ -29,6 +29,7 @@ export class DynamicTableModel extends FormWidgetModel {
|
||||
rows: DynamicTableRow[] = [];
|
||||
|
||||
private _selectedRow: DynamicTableRow;
|
||||
private _validators: CellValidator[] = [];
|
||||
|
||||
get selectedRow(): DynamicTableRow {
|
||||
return this._selectedRow;
|
||||
@ -65,6 +66,11 @@ export class DynamicTableModel extends FormWidgetModel {
|
||||
this.rows = json.value.map(obj => <DynamicTableRow> { selected: false, value: obj });
|
||||
}
|
||||
}
|
||||
|
||||
this._validators = [
|
||||
new RequiredCellValidator(),
|
||||
new NumberCellValidator()
|
||||
];
|
||||
}
|
||||
|
||||
flushValue() {
|
||||
@ -112,6 +118,25 @@ export class DynamicTableModel extends FormWidgetModel {
|
||||
}
|
||||
}
|
||||
|
||||
validateRow(row: DynamicTableRow): DynamicRowValidationSummary {
|
||||
let summary = <DynamicRowValidationSummary> {
|
||||
isValid: true,
|
||||
text: null
|
||||
};
|
||||
|
||||
if (row) {
|
||||
for (let col of this.columns) {
|
||||
for (let validator of this._validators) {
|
||||
if (!validator.validate(row, col, summary)) {
|
||||
return summary;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return summary;
|
||||
}
|
||||
|
||||
getCellValue(row: DynamicTableRow, column: DynamicTableColumn): any {
|
||||
let result = row.value[column.id];
|
||||
|
||||
@ -134,3 +159,90 @@ export class DynamicTableModel extends FormWidgetModel {
|
||||
return result || '';
|
||||
}
|
||||
}
|
||||
|
||||
export interface DynamicRowValidationSummary {
|
||||
|
||||
isValid: boolean;
|
||||
text: string;
|
||||
|
||||
}
|
||||
|
||||
export interface CellValidator {
|
||||
|
||||
isSupported(column: DynamicTableColumn): boolean;
|
||||
validate(row: DynamicTableRow, column: DynamicTableColumn, summary?: DynamicRowValidationSummary): boolean;
|
||||
|
||||
}
|
||||
|
||||
export class RequiredCellValidator implements CellValidator {
|
||||
|
||||
private supportedTypes: string[] = [
|
||||
'String',
|
||||
'Number',
|
||||
'Amount',
|
||||
'Date',
|
||||
'Dropdown'
|
||||
];
|
||||
|
||||
isSupported(column: DynamicTableColumn): boolean {
|
||||
return column && column.required && this.supportedTypes.indexOf(column.type) > -1;
|
||||
}
|
||||
|
||||
validate(row: DynamicTableRow, column: DynamicTableColumn, summary?: DynamicRowValidationSummary): boolean {
|
||||
if (this.isSupported(column)) {
|
||||
let value = row.value[column.id];
|
||||
if (column.required) {
|
||||
if (value === null || value === undefined || value === '') {
|
||||
if (summary) {
|
||||
summary.isValid = false;
|
||||
summary.text = `Field '${column.name}' is required.`;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class NumberCellValidator implements CellValidator {
|
||||
|
||||
private supportedTypes: string[] = [
|
||||
'Number',
|
||||
'Amount'
|
||||
];
|
||||
|
||||
isSupported(column: DynamicTableColumn): boolean {
|
||||
return column && column.required && this.supportedTypes.indexOf(column.type) > -1;
|
||||
}
|
||||
|
||||
isNumber(value: any): boolean {
|
||||
if (value === null || value === undefined || value === '') {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !isNaN(+value);
|
||||
}
|
||||
|
||||
validate(row: DynamicTableRow, column: DynamicTableColumn, summary?: DynamicRowValidationSummary): boolean {
|
||||
|
||||
if (this.isSupported(column)) {
|
||||
let value = row.value[column.id];
|
||||
if (value === null ||
|
||||
value === undefined ||
|
||||
value === '' ||
|
||||
this.isNumber(value)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (summary) {
|
||||
summary.isValid = false;
|
||||
summary.text = `Field '${column.name}' must be a number.`;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -11,10 +11,6 @@
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.dynamic-table-widget__table-editor {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.dynamic-table-widget__invalid .mdl-textfield__input {
|
||||
border-color: #d50000;
|
||||
}
|
||||
|
@ -51,49 +51,12 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div *ngIf="editMode" class="mdl-shadow--2dp">
|
||||
<div class="mdl-grid" *ngFor="let column of content.columns">
|
||||
<div class="mdl-cell mdl-cell--6-col" [ngSwitch]="column.type">
|
||||
<div *ngSwitchCase="'Dropdown'">
|
||||
<alf-dropdown-editor
|
||||
[table]="content"
|
||||
[row]="editRow"
|
||||
[column]="column">
|
||||
</alf-dropdown-editor>
|
||||
</div>
|
||||
<div *ngSwitchCase="'Date'">
|
||||
<alf-date-editor
|
||||
[table]="content"
|
||||
[row]="editRow"
|
||||
[column]="column">
|
||||
</alf-date-editor>
|
||||
</div>
|
||||
<row-editor *ngIf="editMode"
|
||||
[table]="content"
|
||||
[row]="editRow"
|
||||
[column]="column"
|
||||
(save)="onSaveChanges()"
|
||||
(cancel)="onCancelChanges()">
|
||||
</row-editor>
|
||||
|
||||
<div *ngSwitchCase="'Boolean'">
|
||||
<alf-boolean-editor
|
||||
[table]="content"
|
||||
[row]="editRow"
|
||||
[column]="column">
|
||||
</alf-boolean-editor>
|
||||
</div>
|
||||
<div *ngSwitchDefault>
|
||||
<alf-text-editor
|
||||
[table]="content"
|
||||
[row]="editRow"
|
||||
[column]="column">
|
||||
</alf-text-editor>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<button
|
||||
class="mdl-button mdl-js-button mdl-js-ripple-effect"
|
||||
(click)="onCancelChanges()">Cancel</button>
|
||||
<button
|
||||
class="mdl-button mdl-js-button mdl-js-ripple-effect"
|
||||
(click)="onSaveChanges()">Save</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!--<span *ngIf="content.validationSummary" class="mdl-textfield__error">{{content.validationSummary}}</span>-->
|
||||
</div>
|
||||
|
@ -32,12 +32,14 @@ export class DynamicTableWidget extends WidgetComponent implements OnInit {
|
||||
|
||||
editMode: boolean;
|
||||
editRow: DynamicTableRow;
|
||||
validationSummary: string;
|
||||
|
||||
constructor(private elementRef: ElementRef) {
|
||||
super();
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.validationSummary = 'hello world';
|
||||
}
|
||||
|
||||
onRowClicked(row: DynamicTableRow) {
|
||||
|
@ -4,6 +4,8 @@
|
||||
type="checkbox"
|
||||
[attr.id]="column.id"
|
||||
[checked]="table.getCellValue(row, column)"
|
||||
[required]="column.required"
|
||||
[disabled]="!column.editable"
|
||||
(change)="onValueChanged(row, column, $event)">
|
||||
<span class="mdl-checkbox__label">{{column.name}}</span>
|
||||
</label>
|
||||
|
@ -7,6 +7,8 @@
|
||||
[value]="table.getCellValue(row, column)"
|
||||
[attr.id]="column.id"
|
||||
[readonly]="true"
|
||||
[required]="column.required"
|
||||
[disabled]="!column.editable"
|
||||
(onOk)="onDateSelected($event)">
|
||||
<label class="mdl-textfield__label" [attr.for]="column.id">{{column.name}} (d-M-yyyy)</label>
|
||||
</div>
|
||||
|
@ -1,9 +1,11 @@
|
||||
<div>
|
||||
<div class="dropdown-editor">
|
||||
<label [attr.for]="column.id">{{column.name}}</label>
|
||||
<div>
|
||||
<select
|
||||
[value]="value"
|
||||
class="dropdown-editor__select"
|
||||
[value]="value"
|
||||
[required]="column.required"
|
||||
[disabled]="!column.editable"
|
||||
(change)="onValueChanged(row, column, $event)">
|
||||
<option></option>
|
||||
<option *ngFor="let opt of options" [value]="opt.name">{{opt.name}}</option>
|
||||
|
@ -36,24 +36,27 @@ export class DropdownEditorComponent extends CellEditorComponent implements OnIn
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.value = this.table.getCellValue(this.row, this.column);
|
||||
this.options = this.column.options || [];
|
||||
|
||||
let field = this.table.field;
|
||||
if (field && field.restUrl) {
|
||||
this.formService
|
||||
.getRestFieldValuesColumn(
|
||||
field.form.taskId,
|
||||
field.id,
|
||||
this.column.id
|
||||
)
|
||||
.subscribe(
|
||||
(result: DynamicTableColumnOption[]) => {
|
||||
this.column.options = result || [];
|
||||
this.options = this.column.options;
|
||||
},
|
||||
err => this.handleError(err)
|
||||
);
|
||||
if (field) {
|
||||
if (this.column.optionType === 'rest') {
|
||||
this.formService
|
||||
.getRestFieldValuesColumn(
|
||||
field.form.taskId,
|
||||
field.id,
|
||||
this.column.id
|
||||
)
|
||||
.subscribe(
|
||||
(result: DynamicTableColumnOption[]) => {
|
||||
this.column.options = result || [];
|
||||
this.options = this.column.options;
|
||||
this.value = this.table.getCellValue(this.row, this.column);
|
||||
},
|
||||
err => this.handleError(err)
|
||||
);
|
||||
} else {
|
||||
this.options = this.column.options || [];
|
||||
this.value = this.table.getCellValue(this.row, this.column);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,16 @@
|
||||
.row-editor {
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
.row-editor__validation-summary {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.row-editor__invalid .row-editor__validation-summary {
|
||||
padding-left: 16px;
|
||||
padding-right: 16px;
|
||||
padding-top: 8px;
|
||||
padding-bottom: 8px;
|
||||
color: #d50000;
|
||||
visibility: visible;
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
<div class="row-editor mdl-shadow--2dp"
|
||||
[class.row-editor__invalid]="!validationSummary.isValid">
|
||||
<div class="mdl-grid" *ngFor="let column of table.columns">
|
||||
<div class="mdl-cell mdl-cell--6-col" [ngSwitch]="column.type">
|
||||
<div *ngSwitchCase="'Dropdown'">
|
||||
<alf-dropdown-editor
|
||||
[table]="table"
|
||||
[row]="row"
|
||||
[column]="column">
|
||||
</alf-dropdown-editor>
|
||||
</div>
|
||||
<div *ngSwitchCase="'Date'">
|
||||
<alf-date-editor
|
||||
[table]="table"
|
||||
[row]="row"
|
||||
[column]="column">
|
||||
</alf-date-editor>
|
||||
</div>
|
||||
|
||||
<div *ngSwitchCase="'Boolean'">
|
||||
<alf-boolean-editor
|
||||
[table]="table"
|
||||
[row]="row"
|
||||
[column]="column">
|
||||
</alf-boolean-editor>
|
||||
</div>
|
||||
<div *ngSwitchDefault>
|
||||
<alf-text-editor
|
||||
[table]="table"
|
||||
[row]="row"
|
||||
[column]="column">
|
||||
</alf-text-editor>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row-editor__validation-summary" *ngIf="!validationSummary.isValid">{{validationSummary.text}}</div>
|
||||
<div>
|
||||
<button
|
||||
class="mdl-button mdl-js-button mdl-js-ripple-effect"
|
||||
(click)="onCancelChanges()">Cancel</button>
|
||||
<button
|
||||
class="mdl-button mdl-js-button mdl-js-ripple-effect"
|
||||
(click)="onSaveChanges()">Save</button>
|
||||
</div>
|
||||
</div>
|
@ -0,0 +1,73 @@
|
||||
/*!
|
||||
* @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.
|
||||
*/
|
||||
|
||||
import { Component, Input, Output, EventEmitter } from '@angular/core';
|
||||
import { DynamicTableModel, DynamicTableRow, DynamicTableColumn, DynamicRowValidationSummary } from './../../core/index';
|
||||
|
||||
@Component({
|
||||
moduleId: module.id,
|
||||
selector: 'row-editor',
|
||||
templateUrl: './row.editor.html',
|
||||
styleUrls: ['./row.editor.css']
|
||||
})
|
||||
export class RowEditorComponent {
|
||||
|
||||
@Input()
|
||||
table: DynamicTableModel;
|
||||
|
||||
@Input()
|
||||
row: DynamicTableRow;
|
||||
|
||||
@Input()
|
||||
column: DynamicTableColumn;
|
||||
|
||||
@Output()
|
||||
save: EventEmitter<any> = new EventEmitter<any>();
|
||||
|
||||
@Output()
|
||||
cancel: EventEmitter<any> = new EventEmitter<any>();
|
||||
|
||||
validationSummary: DynamicRowValidationSummary = <DynamicRowValidationSummary> { isValid: true, text: null };
|
||||
|
||||
onCancelChanges() {
|
||||
this.cancel.emit({
|
||||
table: this.table,
|
||||
row: this.row,
|
||||
column: this.column
|
||||
});
|
||||
}
|
||||
|
||||
onSaveChanges() {
|
||||
this.validate();
|
||||
if (this.isValid()) {
|
||||
this.save.emit({
|
||||
table: this.table,
|
||||
row: this.row,
|
||||
column: this.column
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private isValid(): boolean {
|
||||
return this.validationSummary && this.validationSummary.isValid;
|
||||
}
|
||||
|
||||
private validate() {
|
||||
this.validationSummary = this.table.validateRow(this.row);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
.text-editor {
|
||||
width: 100%;
|
||||
}
|
@ -1,9 +1,11 @@
|
||||
<div alfresco-mdl-textfield class="dynamic-table-widget__table-editor">
|
||||
<div alfresco-mdl-textfield class="text-editor">
|
||||
<input
|
||||
class="mdl-textfield__input"
|
||||
type="text"
|
||||
[value]="table.getCellValue(row, column)"
|
||||
(keyup)="onValueChanged(row, column, $event)"
|
||||
[required]="column.required"
|
||||
[disabled]="!column.editable"
|
||||
[attr.id]="column.id">
|
||||
<label class="mdl-textfield__label" [attr.for]="column.id">{{column.name}}</label>
|
||||
</div>
|
||||
|
@ -39,6 +39,7 @@ import { DateEditorComponent } from './dynamic-table/editors/date/date.editor';
|
||||
import { DropdownEditorComponent } from './dynamic-table/editors/dropdown/dropdown.editor';
|
||||
import { BooleanEditorComponent } from './dynamic-table/editors/boolean/boolean.editor';
|
||||
import { TextEditorComponent } from './dynamic-table/editors/text/text.editor';
|
||||
import { RowEditorComponent } from './dynamic-table/editors/row.editor';
|
||||
|
||||
// core
|
||||
export * from './widget.component';
|
||||
@ -68,6 +69,7 @@ export * from './amount/amount.widget';
|
||||
export * from './dynamic-table/dynamic-table.widget';
|
||||
|
||||
// editors (dynamic table)
|
||||
export * from './dynamic-table/editors/row.editor';
|
||||
export * from './dynamic-table/editors/date/date.editor';
|
||||
export * from './dynamic-table/editors/dropdown/dropdown.editor';
|
||||
export * from './dynamic-table/editors/boolean/boolean.editor';
|
||||
@ -97,5 +99,6 @@ export const WIDGET_DIRECTIVES: any[] = [
|
||||
DateEditorComponent,
|
||||
DropdownEditorComponent,
|
||||
BooleanEditorComponent,
|
||||
TextEditorComponent
|
||||
TextEditorComponent,
|
||||
RowEditorComponent
|
||||
];
|
||||
|
Loading…
x
Reference in New Issue
Block a user