mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-07-31 17:38:48 +00:00
[ADF-833] DataTable - improve the single and double click event (#1979)
* Improve the single and double click event * Fix unit test
This commit is contained in:
committed by
Eugenio Romano
parent
3ca7503ddb
commit
4e7c5bfdbf
@@ -7,7 +7,6 @@
|
|||||||
<th *ngIf="actions && actionsPosition === 'left'" class="alfresco-datatable__actions-header">
|
<th *ngIf="actions && actionsPosition === 'left'" class="alfresco-datatable__actions-header">
|
||||||
<span class="sr-only">Actions</span>
|
<span class="sr-only">Actions</span>
|
||||||
</th>
|
</th>
|
||||||
|
|
||||||
<!-- Columns -->
|
<!-- Columns -->
|
||||||
<th *ngIf="multiselect">
|
<th *ngIf="multiselect">
|
||||||
<md-checkbox [checked]="isSelectAllChecked" (change)="onSelectAllClick($event)"></md-checkbox>
|
<md-checkbox [checked]="isSelectAllChecked" (change)="onSelectAllClick($event)"></md-checkbox>
|
||||||
@@ -29,7 +28,6 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<ng-container *ngIf="!loading">
|
|
||||||
|
|
||||||
<tr *ngFor="let row of data.getRows(); let idx = index" tabindex="0"
|
<tr *ngFor="let row of data.getRows(); let idx = index" tabindex="0"
|
||||||
class="alfresco-datatable__row"
|
class="alfresco-datatable__row"
|
||||||
@@ -55,40 +53,38 @@
|
|||||||
</ul>
|
</ul>
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td *ngIf="multiselect">
|
<td *ngIf="multiselect">
|
||||||
<md-checkbox [(ngModel)]="row.isSelected"></md-checkbox>
|
<md-checkbox [(ngModel)]="row.isSelected"></md-checkbox>
|
||||||
</td>
|
</td>
|
||||||
<td *ngFor="let col of data.getColumns()"
|
<td *ngFor="let col of data.getColumns()"
|
||||||
class="mdl-data-table__cell--non-numeric non-selectable data-cell {{col.cssClass}}"
|
class="mdl-data-table__cell--non-numeric non-selectable data-cell {{col.cssClass}}"
|
||||||
(click)="onRowClick(row, $event)"
|
(click)="onRowClick(row, $event)"
|
||||||
(dblclick)="onRowDblClick(row, $event)"
|
[context-menu]="getContextMenuActions(row, col)"
|
||||||
[context-menu]="getContextMenuActions(row, col)"
|
[context-menu-enabled]="contextMenu">
|
||||||
[context-menu-enabled]="contextMenu">
|
<div *ngIf="!col.template" class="cell-container">
|
||||||
<div *ngIf="!col.template" class="cell-container">
|
<ng-container [ngSwitch]="col.type">
|
||||||
<ng-container [ngSwitch]="col.type">
|
<div *ngSwitchCase="'image'" class="cell-value">
|
||||||
<div *ngSwitchCase="'image'" class="cell-value">
|
<i *ngIf="isIconValue(row, col)" class="material-icons icon-cell">{{asIconValue(row, col)}}</i>
|
||||||
<i *ngIf="isIconValue(row, col)" class="material-icons icon-cell">{{asIconValue(row,
|
<img *ngIf="!isIconValue(row, col)"
|
||||||
col)}}</i>
|
class="image-cell"
|
||||||
<img *ngIf="!isIconValue(row, col)"
|
alt="{{ iconAltTextKey(data.getValue(row, col)) | translate }}"
|
||||||
class="image-cell"
|
src="{{ data.getValue(row, col) }}"
|
||||||
alt="{{ iconAltTextKey(data.getValue(row, col)) | translate }}"
|
(error)="onImageLoadingError($event)">
|
||||||
src="{{ data.getValue(row, col) }}"
|
</div>
|
||||||
(error)="onImageLoadingError($event)">
|
<div *ngSwitchCase="'icon'" class="cell-value">
|
||||||
</div>
|
<img class="image-cell"
|
||||||
<div *ngSwitchCase="'icon'" class="cell-value">
|
alt="{{ iconAltTextKey(data.getValue(row, col)) | translate }}"
|
||||||
<img class="image-cell"
|
src="{{ data.getValue(row, col) }}"
|
||||||
alt="{{ iconAltTextKey(data.getValue(row, col)) | translate }}"
|
(error)="onImageLoadingError($event)">
|
||||||
src="{{ data.getValue(row, col) }}"
|
</div>
|
||||||
(error)="onImageLoadingError($event)">
|
<div *ngSwitchCase="'date'" class="cell-value"
|
||||||
</div>
|
[attr.data-automation-id]="'date_' + data.getValue(row, col)">
|
||||||
<div *ngSwitchCase="'date'" class="cell-value"
|
<alfresco-datatable-cell [data]="data" [column]="col" [row]="row"></alfresco-datatable-cell>
|
||||||
[attr.data-automation-id]="'date_' + data.getValue(row, col)">
|
</div>
|
||||||
<alfresco-datatable-cell [data]="data" [column]="col" [row]="row"></alfresco-datatable-cell>
|
<div *ngSwitchCase="'text'" class="cell-value"
|
||||||
</div>
|
[attr.data-automation-id]="'text_' + data.getValue(row, col)">
|
||||||
<div *ngSwitchCase="'text'" class="cell-value"
|
<alfresco-datatable-cell [data]="data" [column]="col" [row]="row"></alfresco-datatable-cell>
|
||||||
[attr.data-automation-id]="'text_' + data.getValue(row, col)">
|
</div>
|
||||||
<alfresco-datatable-cell [data]="data" [column]="col" [row]="row"></alfresco-datatable-cell>
|
|
||||||
</div>
|
|
||||||
<span *ngSwitchDefault class="cell-value">
|
<span *ngSwitchDefault class="cell-value">
|
||||||
<!-- empty cell for unknown column type -->
|
<!-- empty cell for unknown column type -->
|
||||||
</span>
|
</span>
|
||||||
@@ -129,8 +125,6 @@
|
|||||||
</ng-template>
|
</ng-template>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</ng-container>
|
|
||||||
|
|
||||||
<tr *ngIf="loading">
|
<tr *ngIf="loading">
|
||||||
<td class="mdl-data-table__cell--non-numeric adf-loading-content-container"
|
<td class="mdl-data-table__cell--non-numeric adf-loading-content-container"
|
||||||
[attr.colspan]="1 + data.getColumns().length">
|
[attr.colspan]="1 + data.getColumns().length">
|
||||||
|
@@ -101,6 +101,7 @@ describe('DataTable', () => {
|
|||||||
);
|
);
|
||||||
const rows = dataTable.data.getRows();
|
const rows = dataTable.data.getRows();
|
||||||
|
|
||||||
|
dataTable.ngOnChanges({});
|
||||||
dataTable.onRowClick(rows[0], null);
|
dataTable.onRowClick(rows[0], null);
|
||||||
expect(rows[0].isSelected).toBeTruthy();
|
expect(rows[0].isSelected).toBeTruthy();
|
||||||
expect(rows[1].isSelected).toBeFalsy();
|
expect(rows[1].isSelected).toBeFalsy();
|
||||||
@@ -121,6 +122,7 @@ describe('DataTable', () => {
|
|||||||
);
|
);
|
||||||
const rows = dataTable.data.getRows();
|
const rows = dataTable.data.getRows();
|
||||||
|
|
||||||
|
dataTable.ngOnChanges({});
|
||||||
dataTable.onRowClick(rows[0], null);
|
dataTable.onRowClick(rows[0], null);
|
||||||
expect(rows[0].isSelected).toBeTruthy();
|
expect(rows[0].isSelected).toBeTruthy();
|
||||||
expect(rows[1].isSelected).toBeFalsy();
|
expect(rows[1].isSelected).toBeFalsy();
|
||||||
@@ -145,6 +147,7 @@ describe('DataTable', () => {
|
|||||||
metaKey: true
|
metaKey: true
|
||||||
});
|
});
|
||||||
|
|
||||||
|
dataTable.ngOnChanges({});
|
||||||
dataTable.onRowClick(rows[0], event);
|
dataTable.onRowClick(rows[0], event);
|
||||||
dataTable.onRowClick(rows[1], event);
|
dataTable.onRowClick(rows[1], event);
|
||||||
|
|
||||||
@@ -212,18 +215,65 @@ describe('DataTable', () => {
|
|||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
dataTable.ngOnChanges({});
|
||||||
dataTable.onRowClick(row, null);
|
dataTable.onRowClick(row, null);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should emit row double-click event', done => {
|
it('should emit double click if there are two single click in 250ms', (done) => {
|
||||||
let row = <DataRow> {};
|
|
||||||
|
|
||||||
dataTable.rowDblClick.subscribe(e => {
|
let row = <DataRow> {};
|
||||||
expect(e.value).toBe(row);
|
dataTable.ngOnChanges({});
|
||||||
|
|
||||||
|
dataTable.rowDblClick.subscribe( () => {
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
dataTable.onRowDblClick(row, null);
|
dataTable.onRowClick(row, null);
|
||||||
|
setTimeout(() => {
|
||||||
|
dataTable.onRowClick(row, null);
|
||||||
|
}
|
||||||
|
, 240);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should emit double click if there are more than two single click in 250ms', (done) => {
|
||||||
|
|
||||||
|
let row = <DataRow> {};
|
||||||
|
dataTable.ngOnChanges({});
|
||||||
|
|
||||||
|
dataTable.rowDblClick.subscribe( () => {
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
dataTable.onRowClick(row, null);
|
||||||
|
setTimeout(() => {
|
||||||
|
|
||||||
|
dataTable.onRowClick(row, null);
|
||||||
|
dataTable.onRowClick(row, null);
|
||||||
|
}
|
||||||
|
, 240);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should emit single click if there are two single click in more than 250ms', (done) => {
|
||||||
|
|
||||||
|
let row = <DataRow> {};
|
||||||
|
let clickCount = 0;
|
||||||
|
|
||||||
|
dataTable.ngOnChanges({});
|
||||||
|
|
||||||
|
dataTable.rowClick.subscribe( () => {
|
||||||
|
clickCount += 1;
|
||||||
|
if (clickCount === 2) {
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
dataTable.onRowClick(row, null);
|
||||||
|
setTimeout(() => {
|
||||||
|
dataTable.onRowClick(row, null);
|
||||||
|
}
|
||||||
|
, 260);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should emit row-click dom event', (done) => {
|
it('should emit row-click dom event', (done) => {
|
||||||
@@ -234,6 +284,7 @@ describe('DataTable', () => {
|
|||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
dataTable.ngOnChanges({});
|
||||||
dataTable.onRowClick(row, null);
|
dataTable.onRowClick(row, null);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -244,8 +295,9 @@ describe('DataTable', () => {
|
|||||||
expect(e.detail.value).toBe(row);
|
expect(e.detail.value).toBe(row);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
dataTable.ngOnChanges({});
|
||||||
dataTable.onRowDblClick(row, null);
|
dataTable.onRowClick(row, null);
|
||||||
|
dataTable.onRowClick(row, null);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should prevent default behaviour on row click event', () => {
|
it('should prevent default behaviour on row click event', () => {
|
||||||
@@ -257,6 +309,7 @@ describe('DataTable', () => {
|
|||||||
|
|
||||||
it('should prevent default behaviour on row double-click event', () => {
|
it('should prevent default behaviour on row double-click event', () => {
|
||||||
let e = jasmine.createSpyObj('event', ['preventDefault']);
|
let e = jasmine.createSpyObj('event', ['preventDefault']);
|
||||||
|
dataTable.ngOnChanges({});
|
||||||
dataTable.ngAfterContentInit();
|
dataTable.ngAfterContentInit();
|
||||||
dataTable.onRowDblClick(null, e);
|
dataTable.onRowDblClick(null, e);
|
||||||
expect(e.preventDefault).toHaveBeenCalled();
|
expect(e.preventDefault).toHaveBeenCalled();
|
||||||
|
@@ -21,6 +21,7 @@ import { DataCellEvent } from './data-cell.event';
|
|||||||
import { DataRowActionEvent } from './data-row-action.event';
|
import { DataRowActionEvent } from './data-row-action.event';
|
||||||
import { DataColumnListComponent } from 'ng2-alfresco-core';
|
import { DataColumnListComponent } from 'ng2-alfresco-core';
|
||||||
import { MdCheckboxChange } from '@angular/material';
|
import { MdCheckboxChange } from '@angular/material';
|
||||||
|
import { Observable, Observer } from 'rxjs/Rx';
|
||||||
|
|
||||||
declare var componentHandler;
|
declare var componentHandler;
|
||||||
|
|
||||||
@@ -89,7 +90,11 @@ export class DataTableComponent implements AfterContentInit, OnChanges {
|
|||||||
|
|
||||||
isSelectAllChecked: boolean = false;
|
isSelectAllChecked: boolean = false;
|
||||||
|
|
||||||
|
private clickObserver: Observer<DataRowEvent>;
|
||||||
|
private click$: Observable<DataRowEvent>;
|
||||||
|
|
||||||
constructor(@Optional() private el: ElementRef) {
|
constructor(@Optional() private el: ElementRef) {
|
||||||
|
this.click$ = new Observable<DataRowEvent>(observer => this.clickObserver = observer).share();
|
||||||
}
|
}
|
||||||
|
|
||||||
ngAfterContentInit() {
|
ngAfterContentInit() {
|
||||||
@@ -111,6 +116,7 @@ export class DataTableComponent implements AfterContentInit, OnChanges {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ngOnChanges(changes: SimpleChanges) {
|
ngOnChanges(changes: SimpleChanges) {
|
||||||
|
this.initAndSubscribeClickStream();
|
||||||
if (this.isPropertyChanged(changes['data'])) {
|
if (this.isPropertyChanged(changes['data'])) {
|
||||||
if (this.isTableEmpty()) {
|
if (this.isTableEmpty()) {
|
||||||
this.initTable();
|
this.initTable();
|
||||||
@@ -140,6 +146,46 @@ export class DataTableComponent implements AfterContentInit, OnChanges {
|
|||||||
return rows.map(row => new ObjectDataRow(row));
|
return rows.map(row => new ObjectDataRow(row));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private initAndSubscribeClickStream() {
|
||||||
|
let singleClickStream = this.click$
|
||||||
|
.buffer(this.click$.debounceTime(250))
|
||||||
|
.map(list => list)
|
||||||
|
.filter(x => x.length === 1);
|
||||||
|
|
||||||
|
singleClickStream.subscribe((obj: DataRowEvent[]) => {
|
||||||
|
let event: DataRowEvent = obj[0];
|
||||||
|
let el = obj[0].sender.el;
|
||||||
|
this.rowClick.emit(event);
|
||||||
|
if (!event.defaultPrevented && el.nativeElement) {
|
||||||
|
el.nativeElement.dispatchEvent(
|
||||||
|
new CustomEvent('row-click', {
|
||||||
|
detail: event,
|
||||||
|
bubbles: true
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let multiClickStream = this.click$
|
||||||
|
.buffer(this.click$.debounceTime(250))
|
||||||
|
.map(list => list)
|
||||||
|
.filter(x => x.length >= 2);
|
||||||
|
|
||||||
|
multiClickStream.subscribe((obj: DataRowEvent[]) => {
|
||||||
|
let event: DataRowEvent = obj[0];
|
||||||
|
let el = obj[0].sender.el;
|
||||||
|
this.rowDblClick.emit(event);
|
||||||
|
if (!event.defaultPrevented && el.nativeElement) {
|
||||||
|
el.nativeElement.dispatchEvent(
|
||||||
|
new CustomEvent('row-dblclick', {
|
||||||
|
detail: event,
|
||||||
|
bubbles: true
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private initTable() {
|
private initTable() {
|
||||||
this.data = new ObjectDataTableAdapter(this.rows, []);
|
this.data = new ObjectDataTableAdapter(this.rows, []);
|
||||||
}
|
}
|
||||||
@@ -190,17 +236,8 @@ export class DataTableComponent implements AfterContentInit, OnChanges {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let event = new DataRowEvent(row, e, this);
|
let dataRowEvent = new DataRowEvent(row, e, this);
|
||||||
this.rowClick.emit(event);
|
this.clickObserver.next(dataRowEvent);
|
||||||
|
|
||||||
if (!event.defaultPrevented && this.el.nativeElement) {
|
|
||||||
this.el.nativeElement.dispatchEvent(
|
|
||||||
new CustomEvent('row-click', {
|
|
||||||
detail: event,
|
|
||||||
bubbles: true
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -217,18 +254,8 @@ export class DataTableComponent implements AfterContentInit, OnChanges {
|
|||||||
if (e) {
|
if (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
}
|
}
|
||||||
|
let dataRowEvent = new DataRowEvent(row, e, this);
|
||||||
let event = new DataRowEvent(row, e, this);
|
this.clickObserver.next(dataRowEvent);
|
||||||
this.rowDblClick.emit(event);
|
|
||||||
|
|
||||||
if (!event.defaultPrevented && this.el.nativeElement) {
|
|
||||||
this.el.nativeElement.dispatchEvent(
|
|
||||||
new CustomEvent('row-dblclick', {
|
|
||||||
detail: event,
|
|
||||||
bubbles: true
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onColumnHeaderClick(column: DataColumn) {
|
onColumnHeaderClick(column: DataColumn) {
|
||||||
|
Reference in New Issue
Block a user