mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-07-24 17:32:15 +00:00
[AAE-4841] - Fix content node selector current selection is lost after uploading files (#6862)
* [AAE-4841] - Preserve current selection when preselecting the newly uploaded nodes * add a method to handle unselection of a preselected row in document list and emit the change * Fix-refactor unselection * Fix document list reload * Partial revert share datatable adapter * try with overwriting datatable selection * Sync datatable selection after every page load * refactor selection/unselection in datatable by using a row id * Fix/Add some unit tests * Move preselection from adapter to doc list, fix single selection mode * Add some unit tests * Add document list unit tests
This commit is contained in:
@@ -19,7 +19,7 @@ import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
|
||||
import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { Node, NodeEntry, NodePaging, RequestScope, ResultSetPaging, SiteEntry, SitePaging } from '@alfresco/js-api';
|
||||
import { AppConfigService, FileModel, FileUploadStatus, NodesApiService, setupTestBed, SitesService, UploadService } from '@alfresco/adf-core';
|
||||
import { AppConfigService, FileModel, FileUploadStatus, NodesApiService, setupTestBed, SitesService, UploadService, FileUploadCompleteEvent } from '@alfresco/adf-core';
|
||||
import { of, throwError } from 'rxjs';
|
||||
import { DropdownBreadcrumbComponent } from '../breadcrumb';
|
||||
import { ContentNodeSelectorPanelComponent } from './content-node-selector-panel.component';
|
||||
@@ -1214,18 +1214,74 @@ describe('ContentNodeSelectorPanelComponent', () => {
|
||||
spyOn(documentListService, 'getFolder');
|
||||
});
|
||||
|
||||
it('should remove the node from the chosenNodes when an upload gets deleted', () => {
|
||||
it('should trigger preselection only after the upload batch contains all the uploads of the queue and no other uploads are in progress', fakeAsync(() => {
|
||||
fixture.detectChanges();
|
||||
const selectSpy = spyOn(component.select, 'next');
|
||||
component.selectionMode = 'multiple';
|
||||
|
||||
const isUploadingSpy = spyOn(uploadService, 'isUploading').and.returnValue(true);
|
||||
const documentListReloadSpy = spyOn(component.documentList, 'reloadWithoutResettingSelection');
|
||||
|
||||
const fakeFileModels = [new FileModel(<File> { name: 'fake-name', size: 100 }), new FileModel(<File> { name: 'fake-name-2', size: 200 })];
|
||||
const fileUploadCompleteEvent = new FileUploadCompleteEvent(fakeFileModels[0], 1, fakeFileModels[0], 0);
|
||||
uploadService.fileUploadComplete.next(fileUploadCompleteEvent);
|
||||
|
||||
tick(500);
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(component.currentUploadBatch).toEqual([fileUploadCompleteEvent.data]);
|
||||
expect(component.preselectedNodes).toEqual([]);
|
||||
expect(documentListReloadSpy).not.toHaveBeenCalled();
|
||||
|
||||
isUploadingSpy.and.returnValue(false);
|
||||
|
||||
const secondFileUploadCompleteEvent = new FileUploadCompleteEvent(fakeFileModels[1], 2, fakeFileModels[1], 0);
|
||||
uploadService.fileUploadComplete.next(secondFileUploadCompleteEvent);
|
||||
tick(500);
|
||||
|
||||
expect(component.currentUploadBatch).toEqual([]);
|
||||
expect(component.preselectedNodes).toEqual([fileUploadCompleteEvent.data, secondFileUploadCompleteEvent.data]);
|
||||
expect(documentListReloadSpy).toHaveBeenCalled();
|
||||
}));
|
||||
|
||||
it('should call document list to unselect the row of the deleted upload', () => {
|
||||
fixture.detectChanges();
|
||||
|
||||
const documentListUnselectRowSpy = spyOn(component.documentList, 'unselectRowFromNodeId');
|
||||
const documentListReloadSpy = spyOn(component.documentList, 'reloadWithoutResettingSelection');
|
||||
const fakeFileModel = new FileModel(<File> { name: 'fake-name', size: 10000000 });
|
||||
const fakeNodes = [<Node> { id: 'fakeNodeId' }, <Node> { id: 'fakeNodeId2' }];
|
||||
|
||||
fakeFileModel.data = { entry: fakeNodes[0] };
|
||||
fakeFileModel.status = FileUploadStatus.Deleted;
|
||||
component._chosenNode = [...fakeNodes];
|
||||
uploadService.cancelUpload(fakeFileModel);
|
||||
|
||||
expect(selectSpy).toHaveBeenCalledWith([fakeNodes[1]]);
|
||||
expect(component._chosenNode).toEqual([fakeNodes[1]]);
|
||||
expect(documentListUnselectRowSpy).toHaveBeenCalledWith(fakeNodes[0].id);
|
||||
expect(documentListReloadSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should return only the last uploaded node to become preselected when the selection mode is single', () => {
|
||||
fixture.detectChanges();
|
||||
const fakeNodes = [new NodeEntry({ id: 'fakeNode1' }), new NodeEntry({ id: 'fakeNode2' })];
|
||||
component.currentUploadBatch = fakeNodes;
|
||||
component.selectionMode = 'single';
|
||||
|
||||
expect(component.getPreselectNodesBasedOnSelectionMode()).toEqual([fakeNodes[1]]);
|
||||
});
|
||||
|
||||
it('should return all the uploaded nodes to become preselected when the selection mode is multiple', () => {
|
||||
fixture.detectChanges();
|
||||
const fakeNodes = [new NodeEntry({ id: 'fakeNode1' }), new NodeEntry({ id: 'fakeNode2' })];
|
||||
component.currentUploadBatch = fakeNodes;
|
||||
component.selectionMode = 'multiple';
|
||||
|
||||
expect(component.getPreselectNodesBasedOnSelectionMode()).toEqual(fakeNodes);
|
||||
});
|
||||
|
||||
it('should return an empty array when no files are uploaded', () => {
|
||||
fixture.detectChanges();
|
||||
component.currentUploadBatch = [];
|
||||
|
||||
expect(component.getPreselectNodesBasedOnSelectionMode()).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
|
@@ -36,7 +36,6 @@ import {
|
||||
UploadService,
|
||||
FileUploadCompleteEvent,
|
||||
FileUploadDeleteEvent,
|
||||
FileModel,
|
||||
AppConfigService,
|
||||
DataSorting
|
||||
} from '@alfresco/adf-core';
|
||||
@@ -45,7 +44,7 @@ import { Node, NodePaging, Pagination, SiteEntry, SitePaging, NodeEntry, QueryBo
|
||||
import { DocumentListComponent } from '../document-list/components/document-list.component';
|
||||
import { RowFilter } from '../document-list/data/row-filter.model';
|
||||
import { ImageResolver } from '../document-list/data/image-resolver.model';
|
||||
import { debounceTime, takeUntil, scan } from 'rxjs/operators';
|
||||
import { debounceTime, takeUntil } from 'rxjs/operators';
|
||||
import { CustomResourcesService } from '../document-list/services/custom-resources.service';
|
||||
import { NodeEntryEvent, ShareDataRow } from '../document-list';
|
||||
import { Subject } from 'rxjs';
|
||||
@@ -253,6 +252,8 @@ export class ContentNodeSelectorPanelComponent implements OnInit, OnDestroy {
|
||||
|
||||
target: PaginatedComponent;
|
||||
preselectedNodes: NodeEntry[] = [];
|
||||
currentUploadBatch: NodeEntry[] = [];
|
||||
|
||||
sorting: string[] | DataSorting;
|
||||
|
||||
searchPanelExpanded: boolean = false;
|
||||
@@ -359,36 +360,29 @@ export class ContentNodeSelectorPanelComponent implements OnInit, OnDestroy {
|
||||
|
||||
private onFileUploadEvent() {
|
||||
this.uploadService.fileUploadComplete
|
||||
.pipe(
|
||||
debounceTime(500),
|
||||
scan((files, currentFile) => [...files, currentFile], []),
|
||||
takeUntil(this.onDestroy$)
|
||||
)
|
||||
.subscribe((uploadedFiles: FileUploadCompleteEvent[]) => {
|
||||
this.preselectedNodes = this.getPreselectNodesBasedOnSelectionMode(uploadedFiles);
|
||||
this.documentList.reload();
|
||||
});
|
||||
.pipe(
|
||||
debounceTime(500),
|
||||
takeUntil(this.onDestroy$)
|
||||
)
|
||||
.subscribe((fileUploadEvent: FileUploadCompleteEvent) => {
|
||||
this.currentUploadBatch.push(fileUploadEvent.data);
|
||||
if (!this.uploadService.isUploading()) {
|
||||
this.preselectedNodes = this.getPreselectNodesBasedOnSelectionMode();
|
||||
this.currentUploadBatch = [];
|
||||
this.documentList.reloadWithoutResettingSelection();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private onFileUploadDeletedEvent() {
|
||||
this.uploadService.fileUploadDeleted
|
||||
.pipe(takeUntil(this.onDestroy$))
|
||||
.subscribe((deletedFileEvent: FileUploadDeleteEvent) => {
|
||||
this.removeFromChosenNodes(deletedFileEvent.file);
|
||||
this.documentList.reload();
|
||||
this.documentList.unselectRowFromNodeId(deletedFileEvent.file.data.entry.id);
|
||||
this.documentList.reloadWithoutResettingSelection();
|
||||
});
|
||||
}
|
||||
|
||||
private removeFromChosenNodes(file: FileModel) {
|
||||
if (this.chosenNode) {
|
||||
const fileIndex = this.chosenNode.findIndex((chosenNode: Node) => chosenNode.id === file.data.entry.id);
|
||||
if (fileIndex !== -1) {
|
||||
this._chosenNode.splice(fileIndex, 1);
|
||||
this.select.next(this._chosenNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private getStartSite() {
|
||||
this.nodesApiService.getNode(this.currentFolderId).subscribe((startNodeEntry) => {
|
||||
this.startSiteGuid = this.sitesService.getSiteNameFromNodePath(startNodeEntry);
|
||||
@@ -462,6 +456,7 @@ export class ContentNodeSelectorPanelComponent implements OnInit, OnDestroy {
|
||||
this.infinitePaginationComponent.reset();
|
||||
}
|
||||
this.folderIdToShow = null;
|
||||
this.preselectedNodes = [];
|
||||
this.loadingSearchResults = true;
|
||||
this.addCorrespondingNodeIdsQuery();
|
||||
this.resetChosenNode();
|
||||
@@ -630,14 +625,14 @@ export class ContentNodeSelectorPanelComponent implements OnInit, OnDestroy {
|
||||
return this.selectionMode === 'single';
|
||||
}
|
||||
|
||||
private getPreselectNodesBasedOnSelectionMode(uploadedFiles: FileUploadCompleteEvent[]): NodeEntry[] {
|
||||
getPreselectNodesBasedOnSelectionMode(): NodeEntry[] {
|
||||
let selectedNodes: NodeEntry[] = [];
|
||||
|
||||
if (uploadedFiles && uploadedFiles.length > 0 ) {
|
||||
if (this.currentUploadBatch?.length) {
|
||||
if (this.isSingleSelectionMode()) {
|
||||
selectedNodes = [...[uploadedFiles[uploadedFiles.length - 1]].map((uploadedFile) => uploadedFile.data)];
|
||||
selectedNodes = [this.currentUploadBatch[this.currentUploadBatch.length - 1]];
|
||||
} else {
|
||||
selectedNodes = [...uploadedFiles.map((uploadedFile) => uploadedFile.data)];
|
||||
selectedNodes = this.currentUploadBatch;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { CUSTOM_ELEMENTS_SCHEMA, SimpleChange, QueryList, Component, ViewChild } from '@angular/core';
|
||||
import { CUSTOM_ELEMENTS_SCHEMA, SimpleChange, QueryList, Component, ViewChild, SimpleChanges } from '@angular/core';
|
||||
import { ComponentFixture, TestBed, fakeAsync, tick } from '@angular/core/testing';
|
||||
import {
|
||||
setupTestBed,
|
||||
@@ -32,13 +32,17 @@ import {
|
||||
} from '@alfresco/adf-core';
|
||||
import { Subject, of, throwError } from 'rxjs';
|
||||
import {
|
||||
FileNode, FolderNode,
|
||||
FileNode,
|
||||
FolderNode,
|
||||
fakeNodeAnswerWithNOEntries,
|
||||
fakeNodeWithNoPermission,
|
||||
fakeGetSitesAnswer,
|
||||
fakeGetSiteMembership,
|
||||
mockPreselectedNodes,
|
||||
mockNodePagingWithPreselectedNodes
|
||||
mockNodePagingWithPreselectedNodes,
|
||||
mockNode1,
|
||||
mockNode2,
|
||||
mockNode3
|
||||
} from '../../mock';
|
||||
import { ContentActionModel } from '../models/content-action.model';
|
||||
import { NodeMinimal, NodeMinimalEntry, NodePaging } from '../models/document-library.model';
|
||||
@@ -236,6 +240,47 @@ describe('DocumentList', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('should not reset the selection when preselectNodes input changes', () => {
|
||||
const resetSelectionSpy = spyOn(documentList, 'resetSelection').and.callThrough();
|
||||
documentList.selection = [{ entry: mockNode3 }];
|
||||
const changes: SimpleChanges = {
|
||||
'preselectNodes': {
|
||||
previousValue: undefined,
|
||||
currentValue: mockPreselectedNodes,
|
||||
firstChange: true,
|
||||
isFirstChange(): boolean { return this.firstChange; }
|
||||
}
|
||||
};
|
||||
documentList.ngOnChanges(changes);
|
||||
|
||||
expect(resetSelectionSpy).not.toHaveBeenCalled();
|
||||
expect(documentList.selection).toEqual([{ entry: mockNode3 }]);
|
||||
});
|
||||
|
||||
it('should reset the selection for every change other than preselectNodes', () => {
|
||||
const resetSelectionSpy = spyOn(documentList, 'resetSelection').and.callThrough();
|
||||
documentList.selection = [{ entry: mockNode3 }];
|
||||
const changes: SimpleChanges = {
|
||||
'mockChange': {
|
||||
previousValue: undefined,
|
||||
currentValue: ['mockChangeValue'],
|
||||
firstChange: true,
|
||||
isFirstChange(): boolean { return this.firstChange; }
|
||||
}
|
||||
};
|
||||
documentList.ngOnChanges(changes);
|
||||
|
||||
expect(resetSelectionSpy).toHaveBeenCalled();
|
||||
expect(documentList.selection).toEqual([]);
|
||||
});
|
||||
|
||||
it('should reloadWithoutResettingSelection not reset the selection', () => {
|
||||
documentList.selection = [{ entry: mockNode3 }];
|
||||
documentList.reloadWithoutResettingSelection();
|
||||
|
||||
expect(documentList.selection).toEqual([{ entry: mockNode3 }]);
|
||||
});
|
||||
|
||||
it('should update schema if columns change', fakeAsync(() => {
|
||||
documentList.columnList = new DataColumnListComponent();
|
||||
documentList.columnList.columns = new QueryList<DataColumnComponent>();
|
||||
@@ -1532,23 +1577,7 @@ describe('DocumentList', () => {
|
||||
spyOn(thumbnailService, 'getMimeTypeIcon').and.returnValue(`assets/images/ft_ic_created.svg`);
|
||||
});
|
||||
|
||||
it('should able to emit nodeSelected event with preselectedNodes on the reload', async () => {
|
||||
const nodeSelectedSpy = spyOn(documentList.nodeSelected, 'emit');
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
documentList.node = mockNodePagingWithPreselectedNodes;
|
||||
documentList.preselectNodes = mockPreselectedNodes;
|
||||
documentList.reload();
|
||||
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
|
||||
expect(documentList.preselectNodes.length).toBe(2);
|
||||
expect(nodeSelectedSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should be able to select first node from the preselectedNodes when selectionMode set to single', async () => {
|
||||
it('should return only the first node of the preselectedNodes when selection mode is single', async () => {
|
||||
documentList.selectionMode = 'single';
|
||||
fixture.detectChanges();
|
||||
|
||||
@@ -1563,7 +1592,7 @@ describe('DocumentList', () => {
|
||||
expect(documentList.getPreselectedNodesBasedOnSelectionMode().length).toBe(1);
|
||||
});
|
||||
|
||||
it('should be able to select all preselectedNodes when selectionMode set to multiple', async () => {
|
||||
it('should return all the preselectedNodes when selection mode is multiple', async () => {
|
||||
documentList.selectionMode = 'multiple';
|
||||
fixture.detectChanges();
|
||||
|
||||
@@ -1581,11 +1610,11 @@ describe('DocumentList', () => {
|
||||
it('should call the datatable select row method for each preselected node', async () => {
|
||||
const datatableSelectRowSpy = spyOn(documentList.dataTable, 'selectRow');
|
||||
const fakeDatatableRows = [new ShareDataRow(mockPreselectedNodes[0], contentService, null), new ShareDataRow(mockPreselectedNodes[1], contentService, null)];
|
||||
spyOn(documentList.data, 'hasPreselectedRows').and.returnValue(true);
|
||||
spyOn(documentList.data, 'getPreselectedRows').and.returnValue(fakeDatatableRows);
|
||||
|
||||
documentList.selectionMode = 'multiple';
|
||||
spyOn(documentList, 'preselectRowsOfPreselectedNodes');
|
||||
documentList.preselectedRows = fakeDatatableRows;
|
||||
documentList.preselectNodes = mockPreselectedNodes;
|
||||
documentList.selectionMode = 'multiple';
|
||||
documentList.onPreselectNodes();
|
||||
|
||||
fixture.detectChanges();
|
||||
@@ -1608,6 +1637,165 @@ describe('DocumentList', () => {
|
||||
|
||||
expect(nodeSelectedSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should return only the first preselected row when selection mode is single', () => {
|
||||
documentList.selectionMode = 'single';
|
||||
const fakeDatatableRows = [new ShareDataRow(mockPreselectedNodes[0], contentService, null), new ShareDataRow(mockPreselectedNodes[1], contentService, null)];
|
||||
documentList.preselectedRows = fakeDatatableRows;
|
||||
const preselectedRows = documentList.getPreselectedRowsBasedOnSelectionMode();
|
||||
|
||||
expect(preselectedRows.length).toEqual(1);
|
||||
expect(preselectedRows[0]).toEqual(fakeDatatableRows[0]);
|
||||
});
|
||||
|
||||
it('should return all the preselected rows when selection mode is multiple', () => {
|
||||
documentList.selectionMode = 'multiple';
|
||||
const fakeDatatableRows = [new ShareDataRow(mockPreselectedNodes[0], contentService, null), new ShareDataRow(mockPreselectedNodes[1], contentService, null)];
|
||||
documentList.preselectedRows = fakeDatatableRows;
|
||||
const preselectedRows = documentList.getPreselectedRowsBasedOnSelectionMode();
|
||||
|
||||
expect(preselectedRows.length).toEqual(2);
|
||||
expect(preselectedRows).toEqual(fakeDatatableRows);
|
||||
});
|
||||
|
||||
it('should return an empty array when there are no preselected rows', () => {
|
||||
documentList.preselectedRows = undefined;
|
||||
const preselectedRows = documentList.getPreselectedRowsBasedOnSelectionMode();
|
||||
|
||||
expect(preselectedRows).toEqual([]);
|
||||
});
|
||||
|
||||
it('should the combined selection be only the first preselected row when selection mode is single', () => {
|
||||
const getSelectionFromAdapterSpy = spyOn(documentList.data, 'getSelectedRows');
|
||||
const fakeDatatableRows = [new ShareDataRow(mockPreselectedNodes[0], contentService, null), new ShareDataRow(mockPreselectedNodes[1], contentService, null)];
|
||||
documentList.preselectedRows = fakeDatatableRows;
|
||||
documentList.selectionMode = 'single';
|
||||
const selection = documentList.getSelectionBasedOnSelectionMode();
|
||||
|
||||
expect(selection.length).toEqual(1);
|
||||
expect(selection[0]).toEqual(fakeDatatableRows[0]);
|
||||
expect(getSelectionFromAdapterSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should get the selection from the adapter when selection mode is multiple', () => {
|
||||
const fakeDatatableRows = [new ShareDataRow(mockPreselectedNodes[0], contentService, null), new ShareDataRow(mockPreselectedNodes[1], contentService, null)];
|
||||
fakeDatatableRows[0].isSelected = true;
|
||||
fakeDatatableRows[1].isSelected = false;
|
||||
documentList.data.setRows(fakeDatatableRows);
|
||||
|
||||
const getSelectionFromAdapterSpy = spyOn(documentList.data, 'getSelectedRows').and.callThrough();
|
||||
documentList.selectionMode = 'multiple';
|
||||
documentList.preselectedRows = fakeDatatableRows;
|
||||
const selection = documentList.getSelectionBasedOnSelectionMode();
|
||||
|
||||
expect(getSelectionFromAdapterSpy).toHaveBeenCalled();
|
||||
expect(selection.length).toEqual(1);
|
||||
expect(selection[0]).toEqual(fakeDatatableRows[0]);
|
||||
});
|
||||
|
||||
it('should preserve the existing selection when selection mode is multiple', () => {
|
||||
fixture.detectChanges();
|
||||
documentList.node = mockNodePagingWithPreselectedNodes;
|
||||
documentList.selection = [{ entry: mockNode1 }, { entry: mockNode2 }];
|
||||
documentList.selectionMode = 'multiple';
|
||||
documentList.reloadWithoutResettingSelection();
|
||||
const selectedRows = documentList.data.getSelectedRows();
|
||||
|
||||
expect(selectedRows.length).toEqual(2);
|
||||
expect(selectedRows[0].id).toEqual(mockNode1.id);
|
||||
expect(selectedRows[0].isSelected).toEqual(true);
|
||||
expect(selectedRows[1].id).toEqual(mockNode2.id);
|
||||
expect(selectedRows[1].isSelected).toEqual(true);
|
||||
});
|
||||
|
||||
it('should not preserve the existing selection when selection mode is single', () => {
|
||||
fixture.detectChanges();
|
||||
documentList.node = mockNodePagingWithPreselectedNodes;
|
||||
documentList.selection = [{ entry: mockNode1 }, { entry: mockNode2 }];
|
||||
documentList.selectionMode = 'single';
|
||||
documentList.reloadWithoutResettingSelection();
|
||||
const selectedRows = documentList.data.getSelectedRows();
|
||||
|
||||
expect(selectedRows.length).toEqual(0);
|
||||
});
|
||||
|
||||
it('should unselect the row from the node id', () => {
|
||||
const datatableSelectRowSpy = spyOn(documentList.dataTable, 'selectRow');
|
||||
const getRowByNodeIdSpy = spyOn(documentList.data, 'getRowByNodeId').and.callThrough();
|
||||
const onNodeUnselectSpy = spyOn(documentList, 'onNodeUnselect');
|
||||
const getSelectionSpy = spyOn(documentList, 'getSelectionBasedOnSelectionMode').and.callThrough();
|
||||
|
||||
const fakeDatatableRows = [new ShareDataRow(mockPreselectedNodes[0], contentService, null), new ShareDataRow(mockPreselectedNodes[1], contentService, null)];
|
||||
fakeDatatableRows[0].isSelected = true;
|
||||
documentList.data.setRows(fakeDatatableRows);
|
||||
let selectedRows = documentList.data.getSelectedRows();
|
||||
|
||||
expect(selectedRows.length).toEqual(1);
|
||||
|
||||
documentList.unselectRowFromNodeId(mockPreselectedNodes[0].entry.id);
|
||||
selectedRows = documentList.data.getSelectedRows();
|
||||
|
||||
expect(selectedRows).toEqual([]);
|
||||
expect(getSelectionSpy).toHaveBeenCalled();
|
||||
expect(getRowByNodeIdSpy).toHaveBeenCalledWith(mockPreselectedNodes[0].entry.id);
|
||||
expect(datatableSelectRowSpy).toHaveBeenCalledWith(fakeDatatableRows[0], false);
|
||||
expect(onNodeUnselectSpy).toHaveBeenCalledWith({ row: undefined, selection: <ShareDataRow[]> selectedRows });
|
||||
});
|
||||
|
||||
it('should preselect the rows of the preselected nodes', () => {
|
||||
const getRowByNodeIdSpy = spyOn(documentList.data, 'getRowByNodeId').and.callThrough();
|
||||
const getPreselectedNodesSpy = spyOn(documentList, 'getPreselectedNodesBasedOnSelectionMode').and.callThrough();
|
||||
|
||||
const fakeDatatableRows = [new ShareDataRow(mockPreselectedNodes[0], contentService, null), new ShareDataRow(mockPreselectedNodes[1], contentService, null)];
|
||||
documentList.data.setRows(fakeDatatableRows);
|
||||
|
||||
documentList.selectionMode = 'multiple';
|
||||
documentList.preselectNodes = [...mockPreselectedNodes, { entry: mockNode3 }];
|
||||
|
||||
documentList.preselectRowsOfPreselectedNodes();
|
||||
const selectedRows = documentList.data.getSelectedRows();
|
||||
|
||||
expect(getPreselectedNodesSpy).toHaveBeenCalled();
|
||||
expect(selectedRows.length).toEqual(2);
|
||||
expect(selectedRows[0].isSelected).toEqual(true);
|
||||
expect(selectedRows[1].isSelected).toEqual(true);
|
||||
|
||||
expect(documentList.preselectedRows.length).toEqual(2);
|
||||
expect(documentList.preselectedRows).toEqual(fakeDatatableRows);
|
||||
|
||||
expect(getRowByNodeIdSpy).toHaveBeenCalledWith(fakeDatatableRows[0].id);
|
||||
expect(getRowByNodeIdSpy).toHaveBeenCalledWith(fakeDatatableRows[1].id);
|
||||
});
|
||||
|
||||
it('should select the rows of the preselected nodes and emit the new combined selection', () => {
|
||||
const hasPreselectedNodesSpy = spyOn(documentList, 'hasPreselectedNodes').and.callThrough();
|
||||
const preselectRowsOfPreselectedNodesSpy = spyOn(documentList, 'preselectRowsOfPreselectedNodes').and.callThrough();
|
||||
const getPreselectedRowsBasedOnSelectionModeSpy = spyOn(documentList, 'getPreselectedRowsBasedOnSelectionMode').and.callThrough();
|
||||
const onNodeSelectSpy = spyOn(documentList, 'onNodeSelect').and.callThrough();
|
||||
|
||||
const fakeDatatableRows = [
|
||||
new ShareDataRow(mockPreselectedNodes[0], contentService, null),
|
||||
new ShareDataRow(mockPreselectedNodes[1], contentService, null),
|
||||
new ShareDataRow({ entry: mockNode3 }, contentService, null)
|
||||
];
|
||||
fakeDatatableRows[2].isSelected = true;
|
||||
documentList.data.setRows(fakeDatatableRows);
|
||||
|
||||
documentList.selection = [{ entry: mockNode3 }];
|
||||
documentList.selectionMode = 'multiple';
|
||||
documentList.preselectNodes = mockPreselectedNodes;
|
||||
documentList.onPreselectNodes();
|
||||
const selectedRows = documentList.data.getSelectedRows();
|
||||
|
||||
expect(hasPreselectedNodesSpy).toHaveBeenCalled();
|
||||
expect(preselectRowsOfPreselectedNodesSpy).toHaveBeenCalled();
|
||||
expect(getPreselectedRowsBasedOnSelectionModeSpy).toHaveBeenCalled();
|
||||
expect(selectedRows.length).toEqual(3);
|
||||
expect(selectedRows[0].id).toEqual(mockNode1.id);
|
||||
expect(selectedRows[1].id).toEqual(mockNode2.id);
|
||||
expect(selectedRows[2].id).toEqual(mockNode3.id);
|
||||
expect(onNodeSelectSpy).toHaveBeenCalledWith({ row: undefined, selection: <ShareDataRow[]> selectedRows });
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
@@ -44,7 +44,8 @@ import {
|
||||
RequestPaginationModel,
|
||||
AlfrescoApiService,
|
||||
UserPreferenceValues,
|
||||
LockService
|
||||
LockService,
|
||||
DataRow
|
||||
} from '@alfresco/adf-core';
|
||||
|
||||
import { Node, NodeEntry, NodePaging, Pagination } from '@alfresco/js-api';
|
||||
@@ -329,6 +330,7 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
|
||||
$folderNode: Subject<Node> = new Subject<Node>();
|
||||
allowFiltering: boolean = true;
|
||||
orderBy: string[] = null;
|
||||
preselectedRows: DataRow[] = [];
|
||||
|
||||
// @deprecated 3.0.0
|
||||
folderNode: Node;
|
||||
@@ -455,7 +457,9 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
|
||||
}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges) {
|
||||
this.resetSelection();
|
||||
if (!changes['preselectNodes']) {
|
||||
this.resetSelection();
|
||||
}
|
||||
|
||||
if (Array.isArray(this.sorting)) {
|
||||
const [key, direction] = this.sorting;
|
||||
@@ -487,7 +491,8 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
|
||||
if (this.data) {
|
||||
if (changes.node && changes.node.currentValue) {
|
||||
const merge = this._pagination ? this._pagination.merge : false;
|
||||
this.data.loadPage(changes.node.currentValue, merge, null, this.getPreselectedNodesBasedOnSelectionMode());
|
||||
this.data.loadPage(changes.node.currentValue, merge, null);
|
||||
this.preserveExistingSelection();
|
||||
this.onPreselectNodes();
|
||||
this.onDataReady(changes.node.currentValue);
|
||||
} else if (changes.imageResolver) {
|
||||
@@ -499,19 +504,24 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
|
||||
reload() {
|
||||
this.ngZone.run(() => {
|
||||
this.resetSelection();
|
||||
if (this.node) {
|
||||
if (this.data) {
|
||||
this.data.loadPage(this.node, this._pagination.merge, null, this.getPreselectedNodesBasedOnSelectionMode());
|
||||
}
|
||||
this.onPreselectNodes();
|
||||
this.syncPagination();
|
||||
this.onDataReady(this.node);
|
||||
} else {
|
||||
this.loadFolder();
|
||||
}
|
||||
this.reloadWithoutResettingSelection();
|
||||
});
|
||||
}
|
||||
|
||||
reloadWithoutResettingSelection() {
|
||||
if (this.node) {
|
||||
if (this.data) {
|
||||
this.data.loadPage(this.node, this._pagination.merge, null);
|
||||
this.preserveExistingSelection();
|
||||
}
|
||||
this.onPreselectNodes();
|
||||
this.syncPagination();
|
||||
this.onDataReady(this.node);
|
||||
} else {
|
||||
this.loadFolder();
|
||||
}
|
||||
}
|
||||
|
||||
contextActionCallback(action) {
|
||||
if (action) {
|
||||
this.executeContentAction(action.node, action.model);
|
||||
@@ -694,7 +704,8 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
|
||||
onPageLoaded(nodePaging: NodePaging) {
|
||||
if (nodePaging) {
|
||||
if (this.data) {
|
||||
this.data.loadPage(nodePaging, this._pagination.merge, this.allowDropFiles, this.getPreselectedNodesBasedOnSelectionMode());
|
||||
this.data.loadPage(nodePaging, this._pagination.merge, this.allowDropFiles);
|
||||
this.preserveExistingSelection();
|
||||
}
|
||||
this.onPreselectNodes();
|
||||
this.setLoadingState(false);
|
||||
@@ -800,7 +811,7 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
|
||||
}
|
||||
|
||||
onNodeSelect(event: { row: ShareDataRow, selection: Array<ShareDataRow> }) {
|
||||
this.selection = event.selection.filter(entry => entry.node).map((entry) => entry.node);
|
||||
this.selection = event.selection.map((entry) => entry.node);
|
||||
const domEvent = new CustomEvent('node-select', {
|
||||
detail: {
|
||||
node: event.row ? event.row.node : null,
|
||||
@@ -923,23 +934,74 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
|
||||
return this.hasPreselectedNodes() ? (this.isSingleSelectionMode() ? [this.preselectNodes[0]] : this.preselectNodes) : [];
|
||||
}
|
||||
|
||||
onPreselectNodes() {
|
||||
if (this.data?.hasPreselectedRows()) {
|
||||
const preselectedNodes = [...this.isSingleSelectionMode() ? [this.data.getPreselectedRows()[0]] : this.data.getPreselectedRows()];
|
||||
const selectedNodes = [...this.selection, ...preselectedNodes];
|
||||
getPreselectedRowsBasedOnSelectionMode(): DataRow[] {
|
||||
return this.hasPreselectedRows() ? (this.isSingleSelectionMode() ? [this.preselectedRows[0]] : this.preselectedRows) : [];
|
||||
}
|
||||
|
||||
for (const node of preselectedNodes) {
|
||||
getSelectionBasedOnSelectionMode(): DataRow[] {
|
||||
return this.hasPreselectedRows() ? (this.isSingleSelectionMode() ? [this.preselectedRows[0]] : this.data.getSelectedRows()) : this.data.getSelectedRows();
|
||||
}
|
||||
|
||||
onPreselectNodes() {
|
||||
if (this.hasPreselectedNodes()) {
|
||||
this.preselectRowsOfPreselectedNodes();
|
||||
const preselectedRows = this.getPreselectedRowsBasedOnSelectionMode();
|
||||
const selectedNodes = this.data.getSelectedRows();
|
||||
|
||||
for (const node of preselectedRows) {
|
||||
this.dataTable.selectRow(node, true);
|
||||
}
|
||||
this.onNodeSelect({ row: undefined, selection: <ShareDataRow[]> selectedNodes });
|
||||
}
|
||||
}
|
||||
|
||||
preserveExistingSelection() {
|
||||
if (this.isMultipleSelectionMode()) {
|
||||
for (const selection of this.selection) {
|
||||
const rowOfSelection = this.data.getRowByNodeId(selection.entry.id);
|
||||
if (rowOfSelection) {
|
||||
rowOfSelection.isSelected = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
preselectRowsOfPreselectedNodes() {
|
||||
this.preselectedRows = [];
|
||||
const preselectedNodes = this.getPreselectedNodesBasedOnSelectionMode();
|
||||
|
||||
preselectedNodes.forEach((preselectedNode: NodeEntry) => {
|
||||
const rowOfPreselectedNode = this.data.getRowByNodeId(preselectedNode.entry.id);
|
||||
if (rowOfPreselectedNode) {
|
||||
rowOfPreselectedNode.isSelected = true;
|
||||
this.preselectedRows.push(rowOfPreselectedNode);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
unselectRowFromNodeId(nodeId: string) {
|
||||
const rowToUnselect = this.data.getRowByNodeId(nodeId);
|
||||
if (rowToUnselect?.isSelected) {
|
||||
rowToUnselect.isSelected = false;
|
||||
this.dataTable.selectRow(rowToUnselect, false);
|
||||
const selection = this.getSelectionBasedOnSelectionMode();
|
||||
this.onNodeUnselect({ row: undefined, selection: <ShareDataRow[]> selection });
|
||||
}
|
||||
}
|
||||
|
||||
isSingleSelectionMode(): boolean {
|
||||
return this.selectionMode === 'single';
|
||||
}
|
||||
|
||||
isMultipleSelectionMode(): boolean {
|
||||
return this.selectionMode === 'multiple';
|
||||
}
|
||||
|
||||
hasPreselectedNodes(): boolean {
|
||||
return this.preselectNodes?.length > 0;
|
||||
}
|
||||
|
||||
hasPreselectedRows(): boolean {
|
||||
return this.preselectedRows?.length > 0;
|
||||
}
|
||||
}
|
||||
|
@@ -27,6 +27,7 @@ export class ShareDataRow implements DataRow {
|
||||
isSelected: boolean = false;
|
||||
isDropTarget: boolean;
|
||||
cssClass: string = '';
|
||||
id: string;
|
||||
|
||||
get node(): NodeEntry {
|
||||
return this.obj;
|
||||
@@ -50,6 +51,7 @@ export class ShareDataRow implements DataRow {
|
||||
if (permissionsStyle) {
|
||||
this.cssClass = this.getPermissionClass(obj);
|
||||
}
|
||||
this.id = this.getId();
|
||||
}
|
||||
|
||||
checkNodeTypeAndPermissions(nodeEntry: NodeEntry) {
|
||||
@@ -118,4 +120,8 @@ export class ShareDataRow implements DataRow {
|
||||
hasValue(key: string): boolean {
|
||||
return this.getValue(key) !== undefined;
|
||||
}
|
||||
|
||||
getId(): string {
|
||||
return this.obj.entry.id || undefined;
|
||||
}
|
||||
}
|
||||
|
@@ -16,7 +16,7 @@
|
||||
*/
|
||||
|
||||
import { DataColumn, DataRow, DataSorting, ContentService, ThumbnailService, setupTestBed } from '@alfresco/adf-core';
|
||||
import { FileNode, FolderNode, SmartFolderNode, RuleFolderNode, LinkFolderNode, mockPreselectedNodes, mockNodePagingWithPreselectedNodes, mockNode2, fakeNodePaging, mockNode1 } from './../../mock';
|
||||
import { FileNode, FolderNode, SmartFolderNode, RuleFolderNode, LinkFolderNode } from './../../mock';
|
||||
import { ShareDataRow } from './share-data-row.model';
|
||||
import { ShareDataTableAdapter } from './share-datatable-adapter';
|
||||
import { ContentTestingModule } from '../../testing/content.testing.module';
|
||||
@@ -480,42 +480,31 @@ describe('ShareDataTableAdapter', () => {
|
||||
|
||||
expect(row.isDropTarget).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Preselect rows', () => {
|
||||
it('should return all the selected rows', () => {
|
||||
const file = new FileNode();
|
||||
const adapter = new ShareDataTableAdapter(thumbnailService, contentService, null);
|
||||
const row1 = new ShareDataRow(file, contentService, null);
|
||||
const row2 = new ShareDataRow(file, contentService, null);
|
||||
const row3 = new ShareDataRow(file, contentService, null);
|
||||
|
||||
it('should set isSelected to be true for each preselectRow if the preselectedNodes are defined', () => {
|
||||
const adapter = new ShareDataTableAdapter(thumbnailService, contentService, []);
|
||||
adapter.loadPage(mockNodePagingWithPreselectedNodes, null, null, mockPreselectedNodes);
|
||||
row1.isSelected = true;
|
||||
row2.isSelected = true;
|
||||
adapter.setRows([row1, row2, row3]);
|
||||
const selectedRows = adapter.getSelectedRows();
|
||||
|
||||
expect(adapter.getPreselectedRows().length).toBe(1);
|
||||
expect(adapter.getPreselectedRows()[0].isSelected).toBe(true);
|
||||
expect(selectedRows.length).toEqual(2);
|
||||
expect(selectedRows).toEqual([row1, row2]);
|
||||
});
|
||||
|
||||
it('should set preselectedRows empty if preselectedNodes are undefined/empty', () => {
|
||||
const adapter = new ShareDataTableAdapter(thumbnailService, contentService, []);
|
||||
adapter.loadPage(mockNodePagingWithPreselectedNodes, null, null, []);
|
||||
it('should return the row of the requested node id', () => {
|
||||
const adapter = new ShareDataTableAdapter(thumbnailService, contentService, null);
|
||||
const fakeFiles = [new FileNode('fake-file-1', 'text/plain', 'fake-node-id-1'), new FileNode('fake-file-2', 'text/plain', 'fake-node-id-2')];
|
||||
const fakeShareDataRows = [new ShareDataRow(fakeFiles[0], contentService, null), new ShareDataRow(fakeFiles[1], contentService, null)];
|
||||
adapter.setRows(fakeShareDataRows);
|
||||
|
||||
expect(adapter.getPreselectedRows().length).toBe(0);
|
||||
});
|
||||
|
||||
it('should set preselectedRows empty if preselectedNodes are not found in the list', () => {
|
||||
const adapter = new ShareDataTableAdapter(thumbnailService, contentService, []);
|
||||
mockNode2.id = 'mock-file-id';
|
||||
const preselectedNode = [ { entry: mockNode2 }];
|
||||
adapter.loadPage(fakeNodePaging, null, null, preselectedNode);
|
||||
|
||||
expect(adapter.getPreselectedRows().length).toBe(0);
|
||||
});
|
||||
|
||||
it('should preselected rows contain only the valid rows that exist in the datatable', () => {
|
||||
const adapter = new ShareDataTableAdapter(thumbnailService, contentService, []);
|
||||
const nonExistingEntry = {...mockNode1};
|
||||
nonExistingEntry.id = 'non-existing-entry-id';
|
||||
const preselectedNodes = [{ entry: nonExistingEntry }, { entry: mockNode1 }, { entry: mockNode2 }];
|
||||
adapter.loadPage(mockNodePagingWithPreselectedNodes, null, null, preselectedNodes);
|
||||
|
||||
expect(adapter.getPreselectedRows().length).toBe(2);
|
||||
expect(adapter.getRowByNodeId('fake-node-id-1')).toEqual(fakeShareDataRows[0]);
|
||||
expect(adapter.getRowByNodeId('fake-node-id-2')).toEqual(fakeShareDataRows[1]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -45,7 +45,6 @@ export class ShareDataTableAdapter implements DataTableAdapter {
|
||||
permissionsStyle: PermissionStyleModel[];
|
||||
selectedRow: DataRow;
|
||||
allowDropFiles: boolean;
|
||||
preselectedRows: DataRow[] = [];
|
||||
|
||||
set sortingMode(value: string) {
|
||||
let newValue = (value || 'client').toLowerCase();
|
||||
@@ -82,10 +81,6 @@ export class ShareDataTableAdapter implements DataTableAdapter {
|
||||
this.sort();
|
||||
}
|
||||
|
||||
getPreselectedRows(): Array<DataRow> {
|
||||
return this.preselectedRows;
|
||||
}
|
||||
|
||||
getColumns(): Array<DataColumn> {
|
||||
return this.columns;
|
||||
}
|
||||
@@ -250,7 +245,7 @@ export class ShareDataTableAdapter implements DataTableAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
public loadPage(nodePaging: NodePaging, merge: boolean = false, allowDropFiles?: boolean, preselectNodes: NodeEntry[] = []) {
|
||||
public loadPage(nodePaging: NodePaging, merge: boolean = false, allowDropFiles?: boolean) {
|
||||
let shareDataRows: ShareDataRow[] = [];
|
||||
if (allowDropFiles !== undefined) {
|
||||
this.allowDropFiles = allowDropFiles;
|
||||
@@ -258,8 +253,7 @@ export class ShareDataTableAdapter implements DataTableAdapter {
|
||||
if (nodePaging?.list) {
|
||||
const nodeEntries: NodeEntry[] = nodePaging.list.entries;
|
||||
if (nodeEntries?.length) {
|
||||
shareDataRows = nodeEntries.map((item) => new ShareDataRow(item, this.contentService, this.permissionsStyle,
|
||||
this.thumbnailService, this.allowDropFiles));
|
||||
shareDataRows = nodeEntries.map((item) => new ShareDataRow(item, this.contentService, this.permissionsStyle, this.thumbnailService, this.allowDropFiles));
|
||||
|
||||
if (this.filter) {
|
||||
shareDataRows = shareDataRows.filter(this.filter);
|
||||
@@ -297,27 +291,13 @@ export class ShareDataTableAdapter implements DataTableAdapter {
|
||||
} else {
|
||||
this.rows = shareDataRows;
|
||||
}
|
||||
|
||||
this.selectRowsBasedOnGivenNodes(preselectNodes);
|
||||
}
|
||||
|
||||
selectRowsBasedOnGivenNodes(preselectNodes: NodeEntry[]) {
|
||||
if (preselectNodes?.length) {
|
||||
this.rows = this.rows.map((row) => {
|
||||
preselectNodes.map((preselectedNode) => {
|
||||
if (row.obj.entry.id === preselectedNode.entry.id) {
|
||||
row.isSelected = true;
|
||||
}
|
||||
});
|
||||
return row;
|
||||
});
|
||||
}
|
||||
|
||||
this.preselectedRows = [...this.rows.filter((res) => res.isSelected)];
|
||||
getSelectedRows(): DataRow[] {
|
||||
return this.rows.filter((row: DataRow) => row.isSelected);
|
||||
}
|
||||
|
||||
hasPreselectedRows(): boolean {
|
||||
return this.preselectedRows?.length > 0;
|
||||
getRowByNodeId(nodeId: string): DataRow {
|
||||
return this.rows.find((row: DataRow) => row.node.entry.id === nodeId);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -33,10 +33,10 @@ export class PageNode extends NodePaging {
|
||||
}
|
||||
|
||||
export class FileNode extends NodeMinimalEntry {
|
||||
constructor(name?: string, mimeType?: string) {
|
||||
constructor(name?: string, mimeType?: string, id?: string) {
|
||||
super();
|
||||
this.entry = new NodeMinimal();
|
||||
this.entry.id = 'file-id';
|
||||
this.entry.id = id || 'file-id';
|
||||
this.entry.isFile = true;
|
||||
this.entry.isFolder = false;
|
||||
this.entry.name = name;
|
||||
|
@@ -308,7 +308,7 @@ export const mockPreselectedNodes: NodeEntry[] = [
|
||||
entry: mockNode1
|
||||
},
|
||||
{
|
||||
entry: mockNode1
|
||||
entry: mockNode2
|
||||
}
|
||||
];
|
||||
|
||||
|
@@ -40,6 +40,7 @@ class CustomColumnTemplateComponent {
|
||||
class FakeDataRow implements DataRow {
|
||||
isDropTarget = false;
|
||||
isSelected = true;
|
||||
id?: string;
|
||||
|
||||
hasValue() {
|
||||
return true;
|
||||
@@ -593,6 +594,45 @@ describe('DataTable', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('should unselect the row searching it by row id, when row id is defined', () => {
|
||||
const findSelectionByIdSpy = spyOn(dataTable, 'findSelectionById');
|
||||
dataTable.data = new ObjectDataTableAdapter([],
|
||||
[new ObjectDataColumn({ key: 'name' })]
|
||||
);
|
||||
|
||||
const fakeDataRows = [new FakeDataRow(), new FakeDataRow()];
|
||||
fakeDataRows[0].id = 'fakeRowId';
|
||||
fakeDataRows[1].id = 'fakeRowId2';
|
||||
|
||||
dataTable.data.setRows(fakeDataRows);
|
||||
dataTable.selection = [...fakeDataRows];
|
||||
const indexOfSpy = spyOn(dataTable.selection, 'indexOf');
|
||||
|
||||
dataTable.selectRow(fakeDataRows[0], false);
|
||||
|
||||
expect(indexOfSpy).not.toHaveBeenCalled();
|
||||
expect(findSelectionByIdSpy).toHaveBeenCalledWith(fakeDataRows[0].id);
|
||||
});
|
||||
|
||||
it('should unselect the row by searching for the exact same reference of it (indexOf), when row id is not defined ', () => {
|
||||
const findSelectionByIdSpy = spyOn(dataTable, 'findSelectionById');
|
||||
dataTable.data = new ObjectDataTableAdapter([],
|
||||
[new ObjectDataColumn({ key: 'name' })]
|
||||
);
|
||||
|
||||
const fakeDataRows = [new FakeDataRow(), new FakeDataRow()];
|
||||
dataTable.data.setRows(fakeDataRows);
|
||||
dataTable.selection = [...fakeDataRows];
|
||||
const indexOfSpy = spyOn(dataTable.selection, 'indexOf').and.returnValue(0);
|
||||
|
||||
dataTable.selectRow(fakeDataRows[0], false);
|
||||
|
||||
expect(indexOfSpy).toHaveBeenCalled();
|
||||
expect(findSelectionByIdSpy).not.toHaveBeenCalled();
|
||||
expect(dataTable.selection.length).toEqual(1);
|
||||
expect(dataTable.selection[0]).toEqual(fakeDataRows[1]);
|
||||
});
|
||||
|
||||
it('should select multiple rows with [multiple] selection mode and modifier key', (done) => {
|
||||
dataTable.selectionMode = 'multiple';
|
||||
dataTable.data = new ObjectDataTableAdapter(
|
||||
|
@@ -710,7 +710,7 @@ export class DataTableComponent implements AfterContentInit, OnChanges, DoCheck,
|
||||
selectRow(row: DataRow, value: boolean) {
|
||||
if (row) {
|
||||
row.isSelected = value;
|
||||
const idx = this.selection.indexOf(row);
|
||||
const idx = row?.id ? this.findSelectionById(row.id) : this.selection.indexOf(row);
|
||||
if (value) {
|
||||
if (idx < 0) {
|
||||
this.selection.push(row);
|
||||
@@ -723,6 +723,10 @@ export class DataTableComponent implements AfterContentInit, OnChanges, DoCheck,
|
||||
}
|
||||
}
|
||||
|
||||
findSelectionById(id: string): number {
|
||||
return this.selection.findIndex(selection => selection?.id === id);
|
||||
}
|
||||
|
||||
getCellTooltip(row: DataRow, col: DataColumn): string {
|
||||
if (row && col && col.formatTooltip) {
|
||||
const result: string = col.formatTooltip(row, col);
|
||||
|
@@ -21,6 +21,7 @@ export interface DataRow {
|
||||
isSelected: boolean;
|
||||
isDropTarget?: boolean;
|
||||
cssClass?: string;
|
||||
id?: string;
|
||||
|
||||
hasValue(key: string): boolean;
|
||||
|
||||
|
Reference in New Issue
Block a user