mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-07-24 17:32:15 +00:00
[ADF-1115] selection management for DT/DL components (#2100)
* row select/unselect dom events for DT - new events for datatable - improved unit tests for empty content placeholders * improved selection management for DT * selection management for document list * fix tests
This commit is contained in:
committed by
Eugenio Romano
parent
6bde12f770
commit
24bd860d38
@@ -62,6 +62,8 @@
|
|||||||
[contextMenuActions]="true"
|
[contextMenuActions]="true"
|
||||||
[contentActions]="true"
|
[contentActions]="true"
|
||||||
[allowDropFiles]="true"
|
[allowDropFiles]="true"
|
||||||
|
[selectionMode]="selectionMode"
|
||||||
|
[multiselect]="multiselect"
|
||||||
(error)="onNavigationError($event)"
|
(error)="onNavigationError($event)"
|
||||||
(success)="resetError()"
|
(success)="resetError()"
|
||||||
(preview)="showFile($event)"
|
(preview)="showFile($event)"
|
||||||
@@ -137,7 +139,20 @@
|
|||||||
|
|
||||||
<context-menu-holder></context-menu-holder>
|
<context-menu-holder></context-menu-holder>
|
||||||
|
|
||||||
|
<div class="p-10">
|
||||||
|
Selected Nodes:
|
||||||
|
<ul>
|
||||||
|
<li *ngFor="let node of documentList.selection">
|
||||||
|
{{ node.entry.name }}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="container">
|
<div class="container">
|
||||||
|
<section>
|
||||||
|
<md-slide-toggle [(ngModel)]="multiselect">Multiselect (with checkboxes)</md-slide-toggle>
|
||||||
|
</section>
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
<md-slide-toggle [(ngModel)]="useDropdownBreadcrumb">Dropdown breadcrumb</md-slide-toggle>
|
<md-slide-toggle [(ngModel)]="useDropdownBreadcrumb">Dropdown breadcrumb</md-slide-toggle>
|
||||||
</section>
|
</section>
|
||||||
@@ -204,6 +219,15 @@
|
|||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="p-10">
|
||||||
|
<p>For 'Multiple' selection mode use Cmd (macOS) or Ctrl (Win) to toggle selection of multiple items.</p>
|
||||||
|
<md-select placeholder="Selection Mode" [(ngModel)]="selectionMode" name="food">
|
||||||
|
<md-option *ngFor="let mode of selectionModes" [value]="mode.value">
|
||||||
|
{{mode.viewValue}}
|
||||||
|
</md-option>
|
||||||
|
</md-select>
|
||||||
|
</div>
|
||||||
|
|
||||||
<file-uploading-dialog #fileDialog></file-uploading-dialog>
|
<file-uploading-dialog #fileDialog></file-uploading-dialog>
|
||||||
|
|
||||||
<div *ngIf="fileShowed">
|
<div *ngIf="fileShowed">
|
||||||
|
@@ -41,6 +41,18 @@ export class FilesComponent implements OnInit {
|
|||||||
useCustomToolbar = true;
|
useCustomToolbar = true;
|
||||||
useDropdownBreadcrumb = true;
|
useDropdownBreadcrumb = true;
|
||||||
|
|
||||||
|
selectionModes = [
|
||||||
|
{ value: 'none', viewValue: 'None' },
|
||||||
|
{ value: 'single', viewValue: 'Single' },
|
||||||
|
{ value: 'multiple', viewValue: 'Multiple' }
|
||||||
|
];
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
selectionMode = 'multiple';
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
multiselect = false;
|
||||||
|
|
||||||
@Input()
|
@Input()
|
||||||
multipleFileUpload: boolean = false;
|
multipleFileUpload: boolean = false;
|
||||||
|
|
||||||
|
@@ -161,6 +161,7 @@ export class DataTableDemo {
|
|||||||
| allowDropFiles | boolean | false | Toggle file drop support for rows (see **ng2-alfresco-core/UploadDirective** for more details) |
|
| allowDropFiles | boolean | false | Toggle file drop support for rows (see **ng2-alfresco-core/UploadDirective** for more details) |
|
||||||
| loading | boolean | false | Flag that indicate if the datable is in loading state and need to show the loading template. Read the documentation above to know how to configure a loading template |
|
| loading | boolean | false | Flag that indicate if the datable is in loading state and need to show the loading template. Read the documentation above to know how to configure a loading template |
|
||||||
| showHeader | boolean | true | Toggles header visibility |
|
| showHeader | boolean | true | Toggles header visibility |
|
||||||
|
| selection | DataRow[] | [] | Contains selected rows |
|
||||||
|
|
||||||
### DataColumn Properties
|
### DataColumn Properties
|
||||||
|
|
||||||
@@ -189,14 +190,17 @@ Here's the list of available properties you can define for a Data Column definit
|
|||||||
|
|
||||||
### DataTable DOM Events
|
### DataTable DOM Events
|
||||||
|
|
||||||
Below are the DOM events raised by DataTable component.
|
Below are the DOM events raised by DataTable component.
|
||||||
|
These events bubble up the component tree and can be handled by any parent component.
|
||||||
|
|
||||||
| Name | Description |
|
| Name | Description |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| row-click | Emitted when user clicks the row |
|
| row-click | Raised when user clicks a row |
|
||||||
| row-dblclick | Emitted when user double-clicks the row |
|
| row-dblclick | Raised when user double-clicks a row |
|
||||||
|
| row-select | Raised after user selects a row |
|
||||||
|
| row-unselect | Raised after user unselects a row |
|
||||||
|
|
||||||
These events are bubbled up the element tree and can be subscribed to from within parent components.
|
For example:
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<root-component (row-click)="onRowClick($event)">
|
<root-component (row-click)="onRowClick($event)">
|
||||||
|
@@ -55,7 +55,10 @@
|
|||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td *ngIf="multiselect">
|
<td *ngIf="multiselect">
|
||||||
<md-checkbox [(ngModel)]="row.isSelected"></md-checkbox>
|
<md-checkbox
|
||||||
|
[checked]="row.isSelected"
|
||||||
|
(change)="onCheckboxChange(row, $event)">
|
||||||
|
</md-checkbox>
|
||||||
</td>
|
</td>
|
||||||
<td *ngFor="let col of data.getColumns()"
|
<td *ngFor="let col of data.getColumns()"
|
||||||
class="adf-data-table-cell adf-data-table-cell--{{col.type || 'text'}} {{col.cssClass}}"
|
class="adf-data-table-cell adf-data-table-cell--{{col.type || 'text'}} {{col.cssClass}}"
|
||||||
|
@@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
AfterContentInit, Component, ContentChild, DoCheck, ElementRef, EventEmitter, Input,
|
AfterContentInit, Component, ContentChild, DoCheck, ElementRef, EventEmitter, Input,
|
||||||
IterableDiffers, OnChanges, Optional, Output, SimpleChange, SimpleChanges, TemplateRef
|
IterableDiffers, OnChanges, Output, SimpleChange, SimpleChanges, TemplateRef
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import { MdCheckboxChange } from '@angular/material';
|
import { MdCheckboxChange } from '@angular/material';
|
||||||
import { AlfrescoTranslationService, DataColumnListComponent } from 'ng2-alfresco-core';
|
import { AlfrescoTranslationService, DataColumnListComponent } from 'ng2-alfresco-core';
|
||||||
@@ -92,10 +92,11 @@ export class DataTableComponent implements AfterContentInit, OnChanges, DoCheck
|
|||||||
@Input()
|
@Input()
|
||||||
loading: boolean = false;
|
loading: boolean = false;
|
||||||
|
|
||||||
public noContentTemplate: TemplateRef<any>;
|
noContentTemplate: TemplateRef<any>;
|
||||||
public loadingTemplate: TemplateRef<any>;
|
loadingTemplate: TemplateRef<any>;
|
||||||
|
|
||||||
isSelectAllChecked: boolean = false;
|
isSelectAllChecked: boolean = false;
|
||||||
|
selection = new Array<DataRow>();
|
||||||
|
|
||||||
private clickObserver: Observer<DataRowEvent>;
|
private clickObserver: Observer<DataRowEvent>;
|
||||||
private click$: Observable<DataRowEvent>;
|
private click$: Observable<DataRowEvent>;
|
||||||
@@ -108,7 +109,7 @@ export class DataTableComponent implements AfterContentInit, OnChanges, DoCheck
|
|||||||
private multiClickStreamSub: Subscription;
|
private multiClickStreamSub: Subscription;
|
||||||
|
|
||||||
constructor(translateService: AlfrescoTranslationService,
|
constructor(translateService: AlfrescoTranslationService,
|
||||||
@Optional() private el: ElementRef,
|
private elementRef: ElementRef,
|
||||||
private differs: IterableDiffers) {
|
private differs: IterableDiffers) {
|
||||||
if (differs) {
|
if (differs) {
|
||||||
this.differ = differs.find([]).create(null);
|
this.differ = differs.find([]).create(null);
|
||||||
@@ -173,10 +174,9 @@ export class DataTableComponent implements AfterContentInit, OnChanges, DoCheck
|
|||||||
|
|
||||||
this.singleClickStreamSub = singleClickStream.subscribe((obj: DataRowEvent[]) => {
|
this.singleClickStreamSub = singleClickStream.subscribe((obj: DataRowEvent[]) => {
|
||||||
let event: DataRowEvent = obj[0];
|
let event: DataRowEvent = obj[0];
|
||||||
let el = obj[0].sender.el;
|
|
||||||
this.rowClick.emit(event);
|
this.rowClick.emit(event);
|
||||||
if (!event.defaultPrevented && el.nativeElement) {
|
if (!event.defaultPrevented) {
|
||||||
el.nativeElement.dispatchEvent(
|
this.elementRef.nativeElement.dispatchEvent(
|
||||||
new CustomEvent('row-click', {
|
new CustomEvent('row-click', {
|
||||||
detail: event,
|
detail: event,
|
||||||
bubbles: true
|
bubbles: true
|
||||||
@@ -192,10 +192,9 @@ export class DataTableComponent implements AfterContentInit, OnChanges, DoCheck
|
|||||||
|
|
||||||
this.multiClickStreamSub = multiClickStream.subscribe((obj: DataRowEvent[]) => {
|
this.multiClickStreamSub = multiClickStream.subscribe((obj: DataRowEvent[]) => {
|
||||||
let event: DataRowEvent = obj[0];
|
let event: DataRowEvent = obj[0];
|
||||||
let el = obj[0].sender.el;
|
|
||||||
this.rowDblClick.emit(event);
|
this.rowDblClick.emit(event);
|
||||||
if (!event.defaultPrevented && el.nativeElement) {
|
if (!event.defaultPrevented) {
|
||||||
el.nativeElement.dispatchEvent(
|
this.elementRef.nativeElement.dispatchEvent(
|
||||||
new CustomEvent('row-dblclick', {
|
new CustomEvent('row-dblclick', {
|
||||||
detail: event,
|
detail: event,
|
||||||
bubbles: true
|
bubbles: true
|
||||||
@@ -247,21 +246,32 @@ export class DataTableComponent implements AfterContentInit, OnChanges, DoCheck
|
|||||||
const newValue = !row.isSelected;
|
const newValue = !row.isSelected;
|
||||||
const rows = this.data.getRows();
|
const rows = this.data.getRows();
|
||||||
|
|
||||||
|
const domEventName = newValue ? 'row-select' : 'row-unselect';
|
||||||
|
const domEvent = new CustomEvent(domEventName, {
|
||||||
|
detail: {
|
||||||
|
row: row,
|
||||||
|
selection: this.selection
|
||||||
|
},
|
||||||
|
bubbles: true
|
||||||
|
});
|
||||||
|
|
||||||
if (this.isSingleSelectionMode()) {
|
if (this.isSingleSelectionMode()) {
|
||||||
rows.forEach(r => r.isSelected = false);
|
this.resetSelection();
|
||||||
row.isSelected = newValue;
|
this.selectRow(row, newValue);
|
||||||
|
this.elementRef.nativeElement.dispatchEvent(domEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.isMultiSelectionMode()) {
|
if (this.isMultiSelectionMode()) {
|
||||||
const modifier = e.metaKey || e.ctrlKey;
|
const modifier = e.metaKey || e.ctrlKey;
|
||||||
if (!modifier) {
|
if (!modifier) {
|
||||||
rows.forEach(r => r.isSelected = false);
|
this.resetSelection();
|
||||||
}
|
}
|
||||||
row.isSelected = newValue;
|
this.selectRow(row, newValue);
|
||||||
|
this.elementRef.nativeElement.dispatchEvent(domEvent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let dataRowEvent = new DataRowEvent(row, e, this);
|
const dataRowEvent = new DataRowEvent(row, e, this);
|
||||||
this.clickObserver.next(dataRowEvent);
|
this.clickObserver.next(dataRowEvent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -272,7 +282,9 @@ export class DataTableComponent implements AfterContentInit, OnChanges, DoCheck
|
|||||||
if (rows && rows.length > 0) {
|
if (rows && rows.length > 0) {
|
||||||
rows.forEach(r => r.isSelected = false);
|
rows.forEach(r => r.isSelected = false);
|
||||||
}
|
}
|
||||||
|
this.selection.splice(0);
|
||||||
}
|
}
|
||||||
|
this.isSelectAllChecked = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
onRowDblClick(row: DataRow, e?: Event) {
|
onRowDblClick(row: DataRow, e?: Event) {
|
||||||
@@ -301,12 +313,29 @@ export class DataTableComponent implements AfterContentInit, OnChanges, DoCheck
|
|||||||
let rows = this.data.getRows();
|
let rows = this.data.getRows();
|
||||||
if (rows && rows.length > 0) {
|
if (rows && rows.length > 0) {
|
||||||
for (let i = 0; i < rows.length; i++) {
|
for (let i = 0; i < rows.length; i++) {
|
||||||
rows[i].isSelected = e.checked;
|
this.selectRow(rows[i], e.checked);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onCheckboxChange(row: DataRow, event: MdCheckboxChange) {
|
||||||
|
const newValue = event.checked;
|
||||||
|
|
||||||
|
this.selectRow(row, newValue);
|
||||||
|
|
||||||
|
const domEventName = newValue ? 'row-select' : 'row-unselect';
|
||||||
|
const domEvent = new CustomEvent(domEventName, {
|
||||||
|
detail: {
|
||||||
|
row: row,
|
||||||
|
selection: this.selection
|
||||||
|
},
|
||||||
|
bubbles: true
|
||||||
|
});
|
||||||
|
|
||||||
|
this.elementRef.nativeElement.dispatchEvent(domEvent);
|
||||||
|
}
|
||||||
|
|
||||||
onImageLoadingError(event: Event) {
|
onImageLoadingError(event: Event) {
|
||||||
if (event && this.fallbackThumbnail) {
|
if (event && this.fallbackThumbnail) {
|
||||||
let element = <any> event.target;
|
let element = <any> event.target;
|
||||||
@@ -384,4 +413,20 @@ export class DataTableComponent implements AfterContentInit, OnChanges, DoCheck
|
|||||||
return `${row.cssClass} ${this.rowStyleClass}`;
|
return `${row.cssClass} ${this.rowStyleClass}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private selectRow(row: DataRow, value: boolean) {
|
||||||
|
if (row) {
|
||||||
|
row.isSelected = value;
|
||||||
|
const idx = this.selection.indexOf(row);
|
||||||
|
|
||||||
|
if (value) {
|
||||||
|
if (idx < 0) {
|
||||||
|
this.selection.push(row);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (idx > -1) {
|
||||||
|
this.selection.splice(idx, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -15,31 +15,42 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Injector } from '@angular/core';
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
import { getTestBed, TestBed } from '@angular/core/testing';
|
|
||||||
import { CoreModule } from 'ng2-alfresco-core';
|
import { CoreModule } from 'ng2-alfresco-core';
|
||||||
|
import { DataTableCellComponent } from '../components/datatable/datatable-cell.component';
|
||||||
import { DataTableComponent } from '../components/datatable/datatable.component';
|
import { DataTableComponent } from '../components/datatable/datatable.component';
|
||||||
|
import { MaterialModule } from '../material.module';
|
||||||
import { LoadingContentTemplateDirective } from './loading-template.directive';
|
import { LoadingContentTemplateDirective } from './loading-template.directive';
|
||||||
|
|
||||||
describe('LoadingContentTemplateDirective', () => {
|
describe('LoadingContentTemplateDirective', () => {
|
||||||
let injector: Injector;
|
|
||||||
let loadingContentTemplateDirective: LoadingContentTemplateDirective;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
let dataTable: DataTableComponent;
|
||||||
|
let directive: LoadingContentTemplateDirective;
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [
|
imports: [
|
||||||
|
MaterialModule,
|
||||||
CoreModule.forRoot()
|
CoreModule.forRoot()
|
||||||
],
|
],
|
||||||
providers: [
|
declarations: [
|
||||||
LoadingContentTemplateDirective,
|
DataTableComponent,
|
||||||
DataTableComponent
|
DataTableCellComponent,
|
||||||
|
LoadingContentTemplateDirective
|
||||||
]
|
]
|
||||||
});
|
}).compileComponents();
|
||||||
injector = getTestBed();
|
}));
|
||||||
loadingContentTemplateDirective = injector.get(LoadingContentTemplateDirective);
|
|
||||||
|
beforeEach(() => {
|
||||||
|
let fixture = TestBed.createComponent(DataTableComponent);
|
||||||
|
dataTable = fixture.componentInstance;
|
||||||
|
directive = new LoadingContentTemplateDirective(dataTable);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('is defined', () => {
|
it('applies template to the datatable', () => {
|
||||||
expect(loadingContentTemplateDirective).toBeDefined();
|
const template = {};
|
||||||
|
directive.template = template;
|
||||||
|
directive.ngAfterContentInit();
|
||||||
|
expect(dataTable.loadingTemplate).toBe(template);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@@ -30,7 +30,9 @@ export class LoadingContentTemplateDirective implements AfterContentInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ngAfterContentInit() {
|
ngAfterContentInit() {
|
||||||
this.dataTable.loadingTemplate = this.template;
|
if (this.dataTable) {
|
||||||
|
this.dataTable.loadingTemplate = this.template;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -15,31 +15,42 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Injector } from '@angular/core';
|
import { async, getTestBed, TestBed } from '@angular/core/testing';
|
||||||
import { getTestBed, TestBed } from '@angular/core/testing';
|
|
||||||
import { CoreModule } from 'ng2-alfresco-core';
|
import { CoreModule } from 'ng2-alfresco-core';
|
||||||
|
import { DataTableCellComponent } from '../components/datatable/datatable-cell.component';
|
||||||
import { DataTableComponent } from '../components/datatable/datatable.component';
|
import { DataTableComponent } from '../components/datatable/datatable.component';
|
||||||
|
import { MaterialModule } from '../material.module';
|
||||||
import { NoContentTemplateDirective } from './no-content-template.directive';
|
import { NoContentTemplateDirective } from './no-content-template.directive';
|
||||||
|
|
||||||
describe('NoContentTemplateDirective', () => {
|
describe('NoContentTemplateDirective', () => {
|
||||||
let injector: Injector;
|
|
||||||
let noContentTemplateDirective: NoContentTemplateDirective;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
let dataTable: DataTableComponent;
|
||||||
|
let directive: NoContentTemplateDirective;
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [
|
imports: [
|
||||||
|
MaterialModule,
|
||||||
CoreModule.forRoot()
|
CoreModule.forRoot()
|
||||||
],
|
],
|
||||||
providers: [
|
declarations: [
|
||||||
NoContentTemplateDirective,
|
DataTableComponent,
|
||||||
DataTableComponent
|
DataTableCellComponent,
|
||||||
|
NoContentTemplateDirective
|
||||||
]
|
]
|
||||||
});
|
}).compileComponents();
|
||||||
injector = getTestBed();
|
}));
|
||||||
noContentTemplateDirective = injector.get(NoContentTemplateDirective);
|
|
||||||
|
beforeEach(() => {
|
||||||
|
let fixture = TestBed.createComponent(DataTableComponent);
|
||||||
|
dataTable = fixture.componentInstance;
|
||||||
|
directive = new NoContentTemplateDirective(dataTable);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('is defined', () => {
|
it('applies template to the datatable', () => {
|
||||||
expect(noContentTemplateDirective).toBeDefined();
|
const template = {};
|
||||||
|
directive.template = template;
|
||||||
|
directive.ngAfterContentInit();
|
||||||
|
expect(dataTable.noContentTemplate).toBe(template);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@@ -30,6 +30,8 @@ export class NoContentTemplateDirective implements AfterContentInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ngAfterContentInit() {
|
ngAfterContentInit() {
|
||||||
this.dataTable.noContentTemplate = this.template;
|
if (this.dataTable) {
|
||||||
|
this.dataTable.noContentTemplate = this.template;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -89,6 +89,7 @@ The properties currentFolderId, folderNode and node are the entry initialization
|
|||||||
| Name | Type | Default | Description |
|
| Name | Type | Default | Description |
|
||||||
| --- | --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
| selectionMode | string | 'single' | Row selection mode. Can be none, `single` or `multiple`. For `multiple` mode you can use Cmd (macOS) or Ctrl (Win) modifier key to toggle selection for multiple rows. |
|
| selectionMode | string | 'single' | Row selection mode. Can be none, `single` or `multiple`. For `multiple` mode you can use Cmd (macOS) or Ctrl (Win) modifier key to toggle selection for multiple rows. |
|
||||||
|
| selection | Array<MinimalNodeEntity> | [] | Contains selected nodes |
|
||||||
| rowStyle | string | | The inline style to apply to every row, see [NgStyle](https://angular.io/docs/ts/latest/api/common/index/NgStyle-directive.html) docs for more details and usage examples |
|
| rowStyle | string | | The inline style to apply to every row, see [NgStyle](https://angular.io/docs/ts/latest/api/common/index/NgStyle-directive.html) docs for more details and usage examples |
|
||||||
| rowStyleClass | string | | The CSS class to apply to every row |
|
| rowStyleClass | string | | The CSS class to apply to every row |
|
||||||
| currentFolderId | string | null | Initial node ID of displayed folder. Can be `-root-`, `-shared-`, `-my-`, or a fixed node ID |
|
| currentFolderId | string | null | Initial node ID of displayed folder. Can be `-root-`, `-shared-`, `-my-`, or a fixed node ID |
|
||||||
@@ -132,6 +133,8 @@ All of them are `bubbling`, meaning you can handle them in any component up the
|
|||||||
| --- | --- |
|
| --- | --- |
|
||||||
| node-click | Raised when user clicks the node |
|
| node-click | Raised when user clicks the node |
|
||||||
| node-dblclick | Raised when user double-clicks the node |
|
| node-dblclick | Raised when user double-clicks the node |
|
||||||
|
| node-select | Raised when user selects a node |
|
||||||
|
| node-unselect | Raised when user unselects a node |
|
||||||
|
|
||||||
Every event is represented by a [CustomEvent](https://developer.mozilla.org/en/docs/Web/API/CustomEvent) instance, having at least the following properties as part of the `Event.detail` property value:
|
Every event is represented by a [CustomEvent](https://developer.mozilla.org/en/docs/Web/API/CustomEvent) instance, having at least the following properties as part of the `Event.detail` property value:
|
||||||
|
|
||||||
@@ -142,6 +145,8 @@ Every event is represented by a [CustomEvent](https://developer.mozilla.org/en/d
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Please refer to the DataTable documentation to find details about additional DOM events the DocumentList component bubbles up from the DataTable.
|
||||||
|
|
||||||
### Handling DOM events
|
### Handling DOM events
|
||||||
|
|
||||||
Here's a basic example on handling DOM events in the parent elements:
|
Here's a basic example on handling DOM events in the parent elements:
|
||||||
|
@@ -20,8 +20,10 @@
|
|||||||
(showRowContextMenu)="onShowRowContextMenu($event)"
|
(showRowContextMenu)="onShowRowContextMenu($event)"
|
||||||
(showRowActionsMenu)="onShowRowActionsMenu($event)"
|
(showRowActionsMenu)="onShowRowActionsMenu($event)"
|
||||||
(executeRowAction)="onExecuteRowAction($event)"
|
(executeRowAction)="onExecuteRowAction($event)"
|
||||||
(rowClick)="onRowClick($event)"
|
(rowClick)="onNodeClick($event.value?.node)"
|
||||||
(rowDblClick)="onRowDblClick($event)">
|
(rowDblClick)="onNodeDblClick($event.value?.node)"
|
||||||
|
(row-select)="onNodeSelect($event.detail)"
|
||||||
|
(row-unselect)="onNodeUnselect($event.detail)">
|
||||||
<div *ngIf="!isEmptyTemplateDefined()">
|
<div *ngIf="!isEmptyTemplateDefined()">
|
||||||
<no-content-template>
|
<no-content-template>
|
||||||
<ng-template>
|
<ng-template>
|
||||||
|
@@ -748,47 +748,43 @@ describe('DocumentList', () => {
|
|||||||
it('should emit [nodeClick] event on row click', () => {
|
it('should emit [nodeClick] event on row click', () => {
|
||||||
let node = new NodeMinimalEntry();
|
let node = new NodeMinimalEntry();
|
||||||
let row = new ShareDataRow(node, null, null);
|
let row = new ShareDataRow(node, null, null);
|
||||||
let event = new DataRowEvent(row, null);
|
|
||||||
|
|
||||||
spyOn(documentList, 'onNodeClick').and.callThrough();
|
spyOn(documentList, 'onNodeClick').and.callThrough();
|
||||||
documentList.onRowClick(event);
|
documentList.onNodeClick(node);
|
||||||
expect(documentList.onNodeClick).toHaveBeenCalledWith(node);
|
expect(documentList.onNodeClick).toHaveBeenCalledWith(node);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should emit node-click DOM event', (done) => {
|
it('should emit node-click DOM event', (done) => {
|
||||||
let node = new NodeMinimalEntry();
|
let node = new NodeMinimalEntry();
|
||||||
let row = new ShareDataRow(node, null, null);
|
let row = new ShareDataRow(node, null, null);
|
||||||
let event = new DataRowEvent(row, null);
|
|
||||||
|
|
||||||
const htmlElement = fixture.debugElement.nativeElement as HTMLElement;
|
const htmlElement = fixture.debugElement.nativeElement as HTMLElement;
|
||||||
htmlElement.addEventListener('node-click', (e: CustomEvent) => {
|
htmlElement.addEventListener('node-click', (e: CustomEvent) => {
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
documentList.onRowClick(event);
|
documentList.onNodeClick(node);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should emit [nodeDblClick] event on row double-click', () => {
|
it('should emit [nodeDblClick] event on row double-click', () => {
|
||||||
let node = new NodeMinimalEntry();
|
let node = new NodeMinimalEntry();
|
||||||
let row = new ShareDataRow(node, null, null);
|
let row = new ShareDataRow(node, null, null);
|
||||||
let event = new DataRowEvent(row, null);
|
|
||||||
|
|
||||||
spyOn(documentList, 'onNodeDblClick').and.callThrough();
|
spyOn(documentList, 'onNodeDblClick').and.callThrough();
|
||||||
documentList.onRowDblClick(event);
|
documentList.onNodeDblClick(node);
|
||||||
expect(documentList.onNodeDblClick).toHaveBeenCalledWith(node);
|
expect(documentList.onNodeDblClick).toHaveBeenCalledWith(node);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should emit node-dblclick DOM event', (done) => {
|
it('should emit node-dblclick DOM event', (done) => {
|
||||||
let node = new NodeMinimalEntry();
|
let node = new NodeMinimalEntry();
|
||||||
let row = new ShareDataRow(node, null, null);
|
let row = new ShareDataRow(node, null, null);
|
||||||
let event = new DataRowEvent(row, null);
|
|
||||||
|
|
||||||
const htmlElement = fixture.debugElement.nativeElement as HTMLElement;
|
const htmlElement = fixture.debugElement.nativeElement as HTMLElement;
|
||||||
htmlElement.addEventListener('node-dblclick', (e: CustomEvent) => {
|
htmlElement.addEventListener('node-dblclick', (e: CustomEvent) => {
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
documentList.onRowDblClick(event);
|
documentList.onNodeDblClick(node);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should load folder by ID on init', () => {
|
it('should load folder by ID on init', () => {
|
||||||
|
@@ -21,7 +21,7 @@ import {
|
|||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import { MinimalNodeEntity, MinimalNodeEntryEntity, NodePaging, Pagination } from 'alfresco-js-api';
|
import { MinimalNodeEntity, MinimalNodeEntryEntity, NodePaging, Pagination } from 'alfresco-js-api';
|
||||||
import { AlfrescoTranslationService, DataColumnListComponent } from 'ng2-alfresco-core';
|
import { AlfrescoTranslationService, DataColumnListComponent } from 'ng2-alfresco-core';
|
||||||
import { DataCellEvent, DataColumn, DataRowActionEvent, DataRowEvent, DataSorting, DataTableComponent, ObjectDataColumn } from 'ng2-alfresco-datatable';
|
import { DataCellEvent, DataColumn, DataRow, DataRowActionEvent, DataRowEvent, DataSorting, DataTableComponent, ObjectDataColumn } from 'ng2-alfresco-datatable';
|
||||||
import { Observable, Subject } from 'rxjs/Rx';
|
import { Observable, Subject } from 'rxjs/Rx';
|
||||||
import { ImageResolver, RowFilter, ShareDataRow, ShareDataTableAdapter } from './../data/share-datatable-adapter';
|
import { ImageResolver, RowFilter, ShareDataRow, ShareDataTableAdapter } from './../data/share-datatable-adapter';
|
||||||
import { ContentActionModel } from './../models/content-action.model';
|
import { ContentActionModel } from './../models/content-action.model';
|
||||||
@@ -98,8 +98,8 @@ export class DocumentListComponent implements OnInit, OnChanges, AfterContentIni
|
|||||||
@Input()
|
@Input()
|
||||||
loading: boolean = false;
|
loading: boolean = false;
|
||||||
|
|
||||||
|
selection = new Array<MinimalNodeEntity>();
|
||||||
skipCount: number = 0;
|
skipCount: number = 0;
|
||||||
|
|
||||||
pagination: Pagination;
|
pagination: Pagination;
|
||||||
|
|
||||||
@Input()
|
@Input()
|
||||||
@@ -166,7 +166,7 @@ export class DocumentListComponent implements OnInit, OnChanges, AfterContentIni
|
|||||||
constructor(private documentListService: DocumentListService,
|
constructor(private documentListService: DocumentListService,
|
||||||
private ngZone: NgZone,
|
private ngZone: NgZone,
|
||||||
translateService: AlfrescoTranslationService,
|
translateService: AlfrescoTranslationService,
|
||||||
private el: ElementRef) {
|
private elementRef: ElementRef) {
|
||||||
|
|
||||||
if (translateService) {
|
if (translateService) {
|
||||||
translateService.addTranslationFolder('ng2-alfresco-documentlist', 'assets/ng2-alfresco-documentlist');
|
translateService.addTranslationFolder('ng2-alfresco-documentlist', 'assets/ng2-alfresco-documentlist');
|
||||||
@@ -390,11 +390,10 @@ export class DocumentListComponent implements OnInit, OnChanges, AfterContentIni
|
|||||||
val => {
|
val => {
|
||||||
if (this.isCurrentPageEmpty(val, skipCount)) {
|
if (this.isCurrentPageEmpty(val, skipCount)) {
|
||||||
this.updateSkipCount(skipCount - maxItems);
|
this.updateSkipCount(skipCount - maxItems);
|
||||||
this.loadFolderNodesByFolderNodeId(id, maxItems, skipCount - maxItems).then(() => {
|
this.loadFolderNodesByFolderNodeId(id, maxItems, skipCount - maxItems).then(
|
||||||
resolve(true);
|
() => resolve(true),
|
||||||
}, (error) => {
|
error => reject(error)
|
||||||
reject(error);
|
);
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
this.data.loadPage(<NodePaging> val);
|
this.data.loadPage(<NodePaging> val);
|
||||||
this.pagination = val.list.pagination;
|
this.pagination = val.list.pagination;
|
||||||
@@ -458,7 +457,7 @@ export class DocumentListComponent implements OnInit, OnChanges, AfterContentIni
|
|||||||
},
|
},
|
||||||
bubbles: true
|
bubbles: true
|
||||||
});
|
});
|
||||||
this.el.nativeElement.dispatchEvent(domEvent);
|
this.elementRef.nativeElement.dispatchEvent(domEvent);
|
||||||
|
|
||||||
const event = new NodeEntityEvent(node);
|
const event = new NodeEntityEvent(node);
|
||||||
this.nodeClick.emit(event);
|
this.nodeClick.emit(event);
|
||||||
@@ -478,11 +477,6 @@ export class DocumentListComponent implements OnInit, OnChanges, AfterContentIni
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onRowClick(event: DataRowEvent) {
|
|
||||||
let item = (<ShareDataRow> event.value).node;
|
|
||||||
this.onNodeClick(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
onNodeDblClick(node: MinimalNodeEntity) {
|
onNodeDblClick(node: MinimalNodeEntity) {
|
||||||
const domEvent = new CustomEvent('node-dblclick', {
|
const domEvent = new CustomEvent('node-dblclick', {
|
||||||
detail: {
|
detail: {
|
||||||
@@ -491,7 +485,7 @@ export class DocumentListComponent implements OnInit, OnChanges, AfterContentIni
|
|||||||
},
|
},
|
||||||
bubbles: true
|
bubbles: true
|
||||||
});
|
});
|
||||||
this.el.nativeElement.dispatchEvent(domEvent);
|
this.elementRef.nativeElement.dispatchEvent(domEvent);
|
||||||
|
|
||||||
const event = new NodeEntityEvent(node);
|
const event = new NodeEntityEvent(node);
|
||||||
this.nodeDblClick.emit(event);
|
this.nodeDblClick.emit(event);
|
||||||
@@ -511,9 +505,26 @@ export class DocumentListComponent implements OnInit, OnChanges, AfterContentIni
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onRowDblClick(event?: DataRowEvent) {
|
onNodeSelect(event: { row: ShareDataRow, selection: Array<ShareDataRow> }) {
|
||||||
let item = (<ShareDataRow> event.value).node;
|
this.selection = event.selection.map(entry => entry.node);
|
||||||
this.onNodeDblClick(item);
|
const domEvent = new CustomEvent('node-select', {
|
||||||
|
detail: {
|
||||||
|
node: event.row.node,
|
||||||
|
selection: this.selection
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.elementRef.nativeElement.dispatchEvent(domEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
onNodeUnselect(event: { row: ShareDataRow, selection: Array<ShareDataRow> }) {
|
||||||
|
this.selection = event.selection.map(entry => entry.node);
|
||||||
|
const domEvent = new CustomEvent('node-unselect', {
|
||||||
|
detail: {
|
||||||
|
node: event.row.node,
|
||||||
|
selection: this.selection
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.elementRef.nativeElement.dispatchEvent(domEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
onShowRowContextMenu(event: DataCellEvent) {
|
onShowRowContextMenu(event: DataCellEvent) {
|
||||||
|
Reference in New Issue
Block a user