Basic editing for dynamic table rows

Editors:
- text (also covers number and amount for now)
- boolean
- dropdown (manual)
- date
This commit is contained in:
Denys Vuika 2016-10-21 16:32:10 +01:00 committed by Vito Albano
parent 4f566a7ba2
commit 51102980df
21 changed files with 513 additions and 58 deletions

View File

@ -17,6 +17,7 @@
export interface DynamicTableRow {
isNew: boolean;
selected: boolean;
value: any;

View File

@ -104,4 +104,24 @@ export class DynamicTableModel extends FormWidgetModel {
}
}
}
getCellValue(row: DynamicTableRow, column: DynamicTableColumn): any {
let result = row.value[column.id];
if (column.type === 'Dropdown') {
return result.name;
}
if (column.type === 'Boolean') {
return result ? true : false;
}
if (column.type === 'Date') {
if (result) {
return moment(result.split('T')[0], 'YYYY-M-D').format('DD-MM-YYYY');
}
}
return result || '';
}
}

View File

@ -11,6 +11,10 @@
width: 100%;
}
.dynamic-table-widget__table-editor {
width: 100%;
}
.dynamic-table-widget__invalid .mdl-textfield__input {
border-color: #d50000;
}

View File

@ -1,7 +1,7 @@
<div class="dynamic-table-widget"
[class.dynamic-table-widget__invalid]="!content.isValid">
<div class="dynamic-table-widget">
<div>{{content.name}}</div>
<div *ngIf="!editMode">
<table class="mdl-data-table mdl-js-data-table dynamic-table-widget__table">
<thead>
<tr>
@ -17,7 +17,7 @@
<td *ngFor="let column of content.visibleColumns"
class="mdl-data-table__cell--non-numeric"
(click)="onRowClicked(row)">
{{row.value[column.id]}}
{{ getCellValue(row, column) }}
</td>
</tr>
</tbody>
@ -49,6 +49,51 @@
<i class="material-icons">edit</i>
</button>
</div>
</div>
<span *ngIf="content.validationSummary" class="mdl-textfield__error">{{content.validationSummary}}</span>
<div *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"
[row]="editRow"
[column]="column">
</alf-dropdown-editor>
</div>
<div *ngSwitchCase="'Date'">
<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>

View File

@ -15,9 +15,9 @@
* limitations under the License.
*/
import { Component, Input, OnInit } from '@angular/core';
import { Component, Input, OnInit, ElementRef } from '@angular/core';
import { WidgetComponent } from './../widget.component';
import { DynamicTableModel, DynamicTableRow } from './../core/index';
import { DynamicTableModel, DynamicTableRow, DynamicTableColumn } from './../core/index';
@Component({
moduleId: module.id,
@ -30,6 +30,13 @@ export class DynamicTableWidget extends WidgetComponent implements OnInit {
@Input()
content: DynamicTableModel;
editMode: boolean;
editRow: DynamicTableRow;
constructor(private elementRef: ElementRef) {
super();
}
ngOnInit() {
}
@ -55,17 +62,67 @@ export class DynamicTableWidget extends WidgetComponent implements OnInit {
}
}
addNewRow() {
console.log('add new row clicked');
}
deleteSelection() {
if (this.content) {
this.content.deleteRow(this.content.selectedRow);
}
}
addNewRow() {
if (this.content) {
this.editRow = <DynamicTableRow> { selected: false, value: {} };
this.editMode = true;
}
}
editSelection() {
console.log('edit selection clicked');
if (this.content) {
this.editRow = this.copyRow(this.content.selectedRow);
this.editMode = true;
}
}
getCellValue(row: DynamicTableRow, column: DynamicTableColumn): any {
if (this.content) {
return this.content.getCellValue(row, column);
}
return null;
}
onSaveChanges() {
if (this.content) {
if (this.editRow.isNew) {
// TODO: create new record
} else {
this.content.selectedRow.value = this.copyObject(this.editRow.value);
}
this.content.flushValue();
}
this.editMode = false;
}
onCancelChanges() {
this.editMode = false;
this.editRow = null;
}
private copyRow(row: DynamicTableRow): DynamicTableRow {
return <DynamicTableRow> {
value: this.copyObject(row.value)
};
}
private copyObject(obj: any): any {
let result = Object.assign({}, obj);
if (typeof obj === 'object' && obj !== null && obj !== undefined) {
Object.keys(obj).forEach(key => {
if (typeof obj[key] === 'object') {
result[key] = this.copyObject(obj[key]);
}
});
}
return result;
}
}

View File

@ -0,0 +1,9 @@
<label class="mdl-checkbox mdl-js-checkbox mdl-js-ripple-effect" [attr.for]="column.id">
<input
class="mdl-checkbox__input"
type="checkbox"
[attr.id]="column.id"
[checked]="table.getCellValue(row, column)"
(change)="onValueChanged(row, column, $event)">
<span class="mdl-checkbox__label">{{column.name}}</span>
</label>

View File

@ -0,0 +1,35 @@
/*!
* @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 } from '@angular/core';
import { CellEditorComponent } from './../cell.editor';
import { DynamicTableRow, DynamicTableColumn } from './../../../core/index';
@Component({
moduleId: module.id,
selector: 'alf-boolean-editor',
templateUrl: './boolean.editor.html',
styleUrls: ['./boolean.editor.css']
})
export class BooleanEditorComponent extends CellEditorComponent {
onValueChanged(row: DynamicTableRow, column: DynamicTableColumn, event: Event) {
let value: boolean = (<HTMLInputElement>event.srcElement).checked;
row.value[column.id] = value;
}
}

View File

@ -0,0 +1,32 @@
/*!
* @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 { Input } from '@angular/core';
import { DynamicTableModel, DynamicTableRow, DynamicTableColumn } from './../../core/index';
export abstract class CellEditorComponent {
@Input()
table: DynamicTableModel;
@Input()
row: DynamicTableRow;
@Input()
column: DynamicTableColumn;
}

View File

@ -0,0 +1,7 @@
.date-editor {
width: 100%;
}
.date-editor--button {
margin-top: 15px;
}

View File

@ -0,0 +1,21 @@
<div class="mdl-grid">
<div class="mdl-cell mdl-cell--11-col">
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label date-editor">
<input id="dateInput"
class="mdl-textfield__input"
type="text"
[value]="table.getCellValue(row, column)"
[attr.id]="column.id"
[readonly]="true"
(onOk)="onDateSelected($event)">
<label class="mdl-textfield__label" [attr.for]="column.id">{{column.name}} (d-M-yyyy)</label>
</div>
</div>
<div class="mdl-cell mdl-cell--1-col">
<button
class="mdl-button mdl-js-button mdl-button--icon date-editor--button"
(click)="datePicker.toggle()">
<i class="material-icons">date_range</i>
</button>
</div>
</div>

View File

@ -0,0 +1,74 @@
/*!
* @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, OnInit, ElementRef } from '@angular/core';
import { CellEditorComponent } from './../cell.editor';
@Component({
moduleId: module.id,
selector: 'alf-date-editor',
templateUrl: './date.editor.html',
styleUrls: ['./date.editor.css']
})
export class DateEditorComponent extends CellEditorComponent implements OnInit {
DATE_FORMAT: string = 'DD-MM-YYYY';
datePicker: any;
constructor(private elementRef: ElementRef) {
super();
}
ngOnInit() {
let settings: any = {
type: 'date',
future: moment().add(21, 'years'),
init: moment(this.table.getCellValue(this.row, this.column), this.DATE_FORMAT)
};
this.datePicker = new mdDateTimePicker.default(settings);
if (this.elementRef) {
this.datePicker.trigger = this.elementRef.nativeElement.querySelector('#dateInput');
}
}
onDateSelected(event: CustomEvent) {
let newValue = this.datePicker.time.format('YYYY-MM-DD');
this.row.value[this.column.id] = newValue + 'T00:00:00.000Z';
this.table.flushValue();
if (this.elementRef) {
this.setupMaterialTextField(this.elementRef, componentHandler, newValue);
}
}
setupMaterialTextField(elementRef: ElementRef, handler: any, value: string): boolean {
if (elementRef && handler) {
let el = elementRef.nativeElement;
if (el) {
let container = el.querySelector('.mdl-textfield');
if (container) {
container.MaterialTextfield.change(value);
return true;
}
}
}
return false;
}
}

View File

@ -0,0 +1,3 @@
.dropdown-editor__select {
width: 100%;
}

View File

@ -0,0 +1,11 @@
<div>
<label [attr.for]="column.id">{{column.name}}</label>
<div>
<select
[value]="table.getCellValue(row, column)"
class="dropdown-editor__select"
(change)="onValueChanged(row, column, $event)">
<option *ngFor="let opt of column.options" [value]="opt.name">{{opt.name}}</option>
</select>
</div>
</div>

View File

@ -0,0 +1,36 @@
/*!
* @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 } from '@angular/core';
import { CellEditorComponent } from './../cell.editor';
import { DynamicTableRow, DynamicTableColumn } from './../../../core/index';
@Component({
moduleId: module.id,
selector: 'alf-dropdown-editor',
templateUrl: './dropdown.editor.html',
styleUrls: ['./dropdown.editor.css']
})
export class DropdownEditorComponent extends CellEditorComponent {
onValueChanged(row: DynamicTableRow, column: DynamicTableColumn, event: Event) {
let value: any = (<HTMLInputElement>event.srcElement).value;
value = column.options.find(opt => opt.name === value);
row.value[column.id] = value;
}
}

View File

@ -0,0 +1,9 @@
<div alfresco-mdl-textfield class="dynamic-table-widget__table-editor">
<input
class="mdl-textfield__input"
type="text"
[value]="table.getCellValue(row, column)"
(keyup)="onValueChanged(row, column, $event)"
[attr.id]="column.id">
<label class="mdl-textfield__label" [attr.for]="column.id">{{column.name}}</label>
</div>

View File

@ -0,0 +1,35 @@
/*!
* @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 } from '@angular/core';
import { CellEditorComponent } from './../cell.editor';
import { DynamicTableRow, DynamicTableColumn } from './../../../core/index';
@Component({
moduleId: module.id,
selector: 'alf-text-editor',
templateUrl: './text.editor.html',
styleUrls: ['./text.editor.css']
})
export class TextEditorComponent extends CellEditorComponent {
onValueChanged(row: DynamicTableRow, column: DynamicTableColumn, event: Event) {
let value: any = (<HTMLInputElement>event.srcElement).value;
row.value[column.id] = value;
}
}

View File

@ -35,6 +35,10 @@ import { PeopleWidget } from './people/people.widget';
import { DateWidget } from './date/date.widget';
import { AmountWidget } from './amount/amount.widget';
import { DynamicTableWidget } from './dynamic-table/dynamic-table.widget';
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';
// core
export * from './widget.component';
@ -63,6 +67,12 @@ export * from './date/date.widget';
export * from './amount/amount.widget';
export * from './dynamic-table/dynamic-table.widget';
// editors (dynamic table)
export * from './dynamic-table/editors/date/date.editor';
export * from './dynamic-table/editors/dropdown/dropdown.editor';
export * from './dynamic-table/editors/boolean/boolean.editor';
export * from './dynamic-table/editors/text/text.editor';
export const WIDGET_DIRECTIVES: any[] = [
TabsWidget,
ContainerWidget,
@ -82,5 +92,10 @@ export const WIDGET_DIRECTIVES: any[] = [
PeopleWidget,
DateWidget,
AmountWidget,
DynamicTableWidget
DynamicTableWidget,
DateEditorComponent,
DropdownEditorComponent,
BooleanEditorComponent,
TextEditorComponent
];

View File

@ -19,15 +19,18 @@ import { MDL } from './MaterialDesignLiteUpgradeElement';
import { AlfrescoMdlButtonDirective } from './mdl-button.directive';
import { AlfrescoMdlMenuDirective } from './mdl-menu.directive';
import { AlfrescoMdlTabsDirective } from './mdl-tabs.directive';
import { AlfrescoMdlTextFieldDirective } from './mdl-textfield.directive';
export * from './MaterialDesignLiteUpgradeElement';
export * from './mdl-button.directive';
export * from './mdl-menu.directive';
export * from './mdl-tabs.directive';
export * from './mdl-textfield.directive';
export const MATERIAL_DESIGN_DIRECTIVES: [any] = [
MDL,
AlfrescoMdlButtonDirective,
AlfrescoMdlMenuDirective,
AlfrescoMdlTabsDirective
AlfrescoMdlTabsDirective,
AlfrescoMdlTextFieldDirective
];

View File

@ -0,0 +1,38 @@
/*!
* @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 { Directive, ElementRef, AfterViewInit } from '@angular/core';
declare var componentHandler;
@Directive({
selector: '[alfresco-mdl-textfield]'
})
export class AlfrescoMdlTextFieldDirective implements AfterViewInit {
constructor(private element: ElementRef) {}
ngAfterViewInit() {
if (componentHandler) {
let el = this.element.nativeElement;
el.classList.add('mdl-textfield');
el.classList.add('mdl-js-textfield');
el.classList.add('mdl-textfield--floating-label');
componentHandler.upgradeElement(el, 'MaterialTextfield');
}
}
}