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[] = [];
|
rows: DynamicTableRow[] = [];
|
||||||
|
|
||||||
private _selectedRow: DynamicTableRow;
|
private _selectedRow: DynamicTableRow;
|
||||||
|
private _validators: CellValidator[] = [];
|
||||||
|
|
||||||
get selectedRow(): DynamicTableRow {
|
get selectedRow(): DynamicTableRow {
|
||||||
return this._selectedRow;
|
return this._selectedRow;
|
||||||
@ -65,6 +66,11 @@ export class DynamicTableModel extends FormWidgetModel {
|
|||||||
this.rows = json.value.map(obj => <DynamicTableRow> { selected: false, value: obj });
|
this.rows = json.value.map(obj => <DynamicTableRow> { selected: false, value: obj });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this._validators = [
|
||||||
|
new RequiredCellValidator(),
|
||||||
|
new NumberCellValidator()
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
flushValue() {
|
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 {
|
getCellValue(row: DynamicTableRow, column: DynamicTableColumn): any {
|
||||||
let result = row.value[column.id];
|
let result = row.value[column.id];
|
||||||
|
|
||||||
@ -134,3 +159,90 @@ export class DynamicTableModel extends FormWidgetModel {
|
|||||||
return result || '';
|
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%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dynamic-table-widget__table-editor {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dynamic-table-widget__invalid .mdl-textfield__input {
|
.dynamic-table-widget__invalid .mdl-textfield__input {
|
||||||
border-color: #d50000;
|
border-color: #d50000;
|
||||||
}
|
}
|
||||||
|
@ -51,49 +51,12 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div *ngIf="editMode" class="mdl-shadow--2dp">
|
<row-editor *ngIf="editMode"
|
||||||
<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"
|
[table]="content"
|
||||||
[row]="editRow"
|
[row]="editRow"
|
||||||
[column]="column">
|
[column]="column"
|
||||||
</alf-dropdown-editor>
|
(save)="onSaveChanges()"
|
||||||
</div>
|
(cancel)="onCancelChanges()">
|
||||||
<div *ngSwitchCase="'Date'">
|
</row-editor>
|
||||||
<alf-date-editor
|
|
||||||
[table]="content"
|
|
||||||
[row]="editRow"
|
|
||||||
[column]="column">
|
|
||||||
</alf-date-editor>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<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>
|
</div>
|
||||||
|
@ -32,12 +32,14 @@ export class DynamicTableWidget extends WidgetComponent implements OnInit {
|
|||||||
|
|
||||||
editMode: boolean;
|
editMode: boolean;
|
||||||
editRow: DynamicTableRow;
|
editRow: DynamicTableRow;
|
||||||
|
validationSummary: string;
|
||||||
|
|
||||||
constructor(private elementRef: ElementRef) {
|
constructor(private elementRef: ElementRef) {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
|
this.validationSummary = 'hello world';
|
||||||
}
|
}
|
||||||
|
|
||||||
onRowClicked(row: DynamicTableRow) {
|
onRowClicked(row: DynamicTableRow) {
|
||||||
|
@ -4,6 +4,8 @@
|
|||||||
type="checkbox"
|
type="checkbox"
|
||||||
[attr.id]="column.id"
|
[attr.id]="column.id"
|
||||||
[checked]="table.getCellValue(row, column)"
|
[checked]="table.getCellValue(row, column)"
|
||||||
|
[required]="column.required"
|
||||||
|
[disabled]="!column.editable"
|
||||||
(change)="onValueChanged(row, column, $event)">
|
(change)="onValueChanged(row, column, $event)">
|
||||||
<span class="mdl-checkbox__label">{{column.name}}</span>
|
<span class="mdl-checkbox__label">{{column.name}}</span>
|
||||||
</label>
|
</label>
|
||||||
|
@ -7,6 +7,8 @@
|
|||||||
[value]="table.getCellValue(row, column)"
|
[value]="table.getCellValue(row, column)"
|
||||||
[attr.id]="column.id"
|
[attr.id]="column.id"
|
||||||
[readonly]="true"
|
[readonly]="true"
|
||||||
|
[required]="column.required"
|
||||||
|
[disabled]="!column.editable"
|
||||||
(onOk)="onDateSelected($event)">
|
(onOk)="onDateSelected($event)">
|
||||||
<label class="mdl-textfield__label" [attr.for]="column.id">{{column.name}} (d-M-yyyy)</label>
|
<label class="mdl-textfield__label" [attr.for]="column.id">{{column.name}} (d-M-yyyy)</label>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
<div>
|
<div class="dropdown-editor">
|
||||||
<label [attr.for]="column.id">{{column.name}}</label>
|
<label [attr.for]="column.id">{{column.name}}</label>
|
||||||
<div>
|
<div>
|
||||||
<select
|
<select
|
||||||
[value]="value"
|
|
||||||
class="dropdown-editor__select"
|
class="dropdown-editor__select"
|
||||||
|
[value]="value"
|
||||||
|
[required]="column.required"
|
||||||
|
[disabled]="!column.editable"
|
||||||
(change)="onValueChanged(row, column, $event)">
|
(change)="onValueChanged(row, column, $event)">
|
||||||
<option></option>
|
<option></option>
|
||||||
<option *ngFor="let opt of options" [value]="opt.name">{{opt.name}}</option>
|
<option *ngFor="let opt of options" [value]="opt.name">{{opt.name}}</option>
|
||||||
|
@ -36,11 +36,9 @@ export class DropdownEditorComponent extends CellEditorComponent implements OnIn
|
|||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.value = this.table.getCellValue(this.row, this.column);
|
|
||||||
this.options = this.column.options || [];
|
|
||||||
|
|
||||||
let field = this.table.field;
|
let field = this.table.field;
|
||||||
if (field && field.restUrl) {
|
if (field) {
|
||||||
|
if (this.column.optionType === 'rest') {
|
||||||
this.formService
|
this.formService
|
||||||
.getRestFieldValuesColumn(
|
.getRestFieldValuesColumn(
|
||||||
field.form.taskId,
|
field.form.taskId,
|
||||||
@ -51,9 +49,14 @@ export class DropdownEditorComponent extends CellEditorComponent implements OnIn
|
|||||||
(result: DynamicTableColumnOption[]) => {
|
(result: DynamicTableColumnOption[]) => {
|
||||||
this.column.options = result || [];
|
this.column.options = result || [];
|
||||||
this.options = this.column.options;
|
this.options = this.column.options;
|
||||||
|
this.value = this.table.getCellValue(this.row, this.column);
|
||||||
},
|
},
|
||||||
err => this.handleError(err)
|
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
|
<input
|
||||||
class="mdl-textfield__input"
|
class="mdl-textfield__input"
|
||||||
type="text"
|
type="text"
|
||||||
[value]="table.getCellValue(row, column)"
|
[value]="table.getCellValue(row, column)"
|
||||||
(keyup)="onValueChanged(row, column, $event)"
|
(keyup)="onValueChanged(row, column, $event)"
|
||||||
|
[required]="column.required"
|
||||||
|
[disabled]="!column.editable"
|
||||||
[attr.id]="column.id">
|
[attr.id]="column.id">
|
||||||
<label class="mdl-textfield__label" [attr.for]="column.id">{{column.name}}</label>
|
<label class="mdl-textfield__label" [attr.for]="column.id">{{column.name}}</label>
|
||||||
</div>
|
</div>
|
||||||
|
@ -39,6 +39,7 @@ import { DateEditorComponent } from './dynamic-table/editors/date/date.editor';
|
|||||||
import { DropdownEditorComponent } from './dynamic-table/editors/dropdown/dropdown.editor';
|
import { DropdownEditorComponent } from './dynamic-table/editors/dropdown/dropdown.editor';
|
||||||
import { BooleanEditorComponent } from './dynamic-table/editors/boolean/boolean.editor';
|
import { BooleanEditorComponent } from './dynamic-table/editors/boolean/boolean.editor';
|
||||||
import { TextEditorComponent } from './dynamic-table/editors/text/text.editor';
|
import { TextEditorComponent } from './dynamic-table/editors/text/text.editor';
|
||||||
|
import { RowEditorComponent } from './dynamic-table/editors/row.editor';
|
||||||
|
|
||||||
// core
|
// core
|
||||||
export * from './widget.component';
|
export * from './widget.component';
|
||||||
@ -68,6 +69,7 @@ export * from './amount/amount.widget';
|
|||||||
export * from './dynamic-table/dynamic-table.widget';
|
export * from './dynamic-table/dynamic-table.widget';
|
||||||
|
|
||||||
// editors (dynamic table)
|
// editors (dynamic table)
|
||||||
|
export * from './dynamic-table/editors/row.editor';
|
||||||
export * from './dynamic-table/editors/date/date.editor';
|
export * from './dynamic-table/editors/date/date.editor';
|
||||||
export * from './dynamic-table/editors/dropdown/dropdown.editor';
|
export * from './dynamic-table/editors/dropdown/dropdown.editor';
|
||||||
export * from './dynamic-table/editors/boolean/boolean.editor';
|
export * from './dynamic-table/editors/boolean/boolean.editor';
|
||||||
@ -97,5 +99,6 @@ export const WIDGET_DIRECTIVES: any[] = [
|
|||||||
DateEditorComponent,
|
DateEditorComponent,
|
||||||
DropdownEditorComponent,
|
DropdownEditorComponent,
|
||||||
BooleanEditorComponent,
|
BooleanEditorComponent,
|
||||||
TextEditorComponent
|
TextEditorComponent,
|
||||||
|
RowEditorComponent
|
||||||
];
|
];
|
||||||
|
Loading…
x
Reference in New Issue
Block a user