Skip to content

Commit 9e2480f

Browse files
FrancescoMolinaroatarix83
authored andcommitted
Merged in task/dspace-cris-2023_02_x/DSC-2288 (pull request DSpace#3055)
[DSC-2288] fix tree loading when value is selected Approved-by: Giuseppe Digilio
2 parents ec6d304 + 0502e19 commit 9e2480f

5 files changed

Lines changed: 69 additions & 26 deletions

File tree

src/app/shared/form/vocabulary-treeview-modal/vocabulary-treeview-modal.component.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ <h4 class="modal-title">{{'vocabulary-treeview.header' | translate}}</h4>
1111
[preloadLevel]="preloadLevel"
1212
[selectedItems]="selectedItems"
1313
[multiSelect]="multiSelect"
14+
[loadAllNodes]="true"
1415
(select)="onSelect($event)">
1516
</ds-vocabulary-treeview>
1617
</div>

src/app/shared/form/vocabulary-treeview/vocabulary-treeview.component.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ <h2 *ngIf="!(loading | async) && dataSource.data.length === 0" class="h4 text-ce
2626
<span>{{'vocabulary-treeview.search.no-result' | translate}}</span>
2727
</h2>
2828
</div>
29-
<cdk-tree [dataSource]="dataSource" [treeControl]="treeControl">
29+
<cdk-tree *ngIf="!(loading | async) && dataSource.data.length !== 0" [dataSource]="dataSource" [treeControl]="treeControl">
3030
<!-- Leaf node -->
3131
<cdk-tree-node *cdkTreeNodeDef="let node" cdkTreeNodePadding class="d-flex">
3232
<span aria-hidden="true" type="button" class="btn btn-default px-2 mr-1" cdkTreeNodeToggle>

src/app/shared/form/vocabulary-treeview/vocabulary-treeview.component.spec.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ describe('VocabularyTreeviewComponent test suite', () => {
131131
comp.selectedItems = [currentValue];
132132
fixture.detectChanges();
133133
expect(comp.dataSource.data).toEqual([]);
134-
expect(vocabularyTreeviewServiceStub.initialize).toHaveBeenCalledWith(comp.vocabularyOptions, new PageInfo(), ['entryID'], 'entryID');
134+
expect(vocabularyTreeviewServiceStub.initialize).toHaveBeenCalledWith(comp.vocabularyOptions, new PageInfo(), ['entryID'], 'entryID', false);
135135
});
136136

137137
it('should should init component properly with init value as VocabularyEntry', () => {
@@ -143,7 +143,7 @@ describe('VocabularyTreeviewComponent test suite', () => {
143143
comp.selectedItems = [currentValue];
144144
fixture.detectChanges();
145145
expect(comp.dataSource.data).toEqual([]);
146-
expect(vocabularyTreeviewServiceStub.initialize).toHaveBeenCalledWith(comp.vocabularyOptions, new PageInfo(), ['entryID'], 'entryID');
146+
expect(vocabularyTreeviewServiceStub.initialize).toHaveBeenCalledWith(comp.vocabularyOptions, new PageInfo(), ['entryID'], 'entryID', false);
147147
});
148148

149149
it('should should init component properly with init value as VocabularyEntryDetail', () => {
@@ -153,7 +153,7 @@ describe('VocabularyTreeviewComponent test suite', () => {
153153
comp.selectedItems = [currentValue];
154154
fixture.detectChanges();
155155
expect(comp.dataSource.data).toEqual([]);
156-
expect(vocabularyTreeviewServiceStub.initialize).toHaveBeenCalledWith(comp.vocabularyOptions, new PageInfo(), ['entryID'], 'entryID');
156+
expect(vocabularyTreeviewServiceStub.initialize).toHaveBeenCalledWith(comp.vocabularyOptions, new PageInfo(), ['entryID'], 'entryID', false);
157157
});
158158

159159
it('should call loadMore function', () => {
@@ -173,7 +173,7 @@ describe('VocabularyTreeviewComponent test suite', () => {
173173
const node = new TreeviewFlatNode(item);
174174
comp.loadChildren(node);
175175
fixture.detectChanges();
176-
expect(vocabularyTreeviewServiceStub.loadMore).toHaveBeenCalledWith(node.item, [], true);
176+
expect(vocabularyTreeviewServiceStub.loadMore).toHaveBeenCalledWith(node.item, [], true, false);
177177
});
178178

179179
it('should emit proper FormFieldMetadataValueObject when VocabularyEntryDetail has authority', () => {

src/app/shared/form/vocabulary-treeview/vocabulary-treeview.component.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,12 @@ export class VocabularyTreeviewComponent implements OnDestroy, OnInit, OnChanges
6262
*/
6363
@Input() selectedItems: VocabularyTreeItemType[] = [];
6464

65+
/**
66+
* Whether to load all available nodes
67+
*/
68+
@Input() loadAllNodes = false;
69+
70+
6571
/**
6672
* A map containing the current node showed by the tree
6773
*/
@@ -217,7 +223,7 @@ export class VocabularyTreeviewComponent implements OnDestroy, OnInit, OnChanges
217223
this.loading = this.vocabularyTreeviewService.isLoading();
218224

219225
const entryId: string = (this.selectedItems?.length > 0) ? this.getEntryId(this.selectedItems[0]) : null;
220-
this.vocabularyTreeviewService.initialize(this.vocabularyOptions, new PageInfo(), this.getSelectedEntryIds(), entryId);
226+
this.vocabularyTreeviewService.initialize(this.vocabularyOptions, new PageInfo(), this.getSelectedEntryIds(), entryId, this.loadAllNodes);
221227
}
222228

223229
/**
@@ -241,7 +247,7 @@ export class VocabularyTreeviewComponent implements OnDestroy, OnInit, OnChanges
241247
* @param node The TreeviewFlatNode for which to load children nodes
242248
*/
243249
loadChildren(node: TreeviewFlatNode) {
244-
this.vocabularyTreeviewService.loadMore(node.item, this.getSelectedEntryIds(), true);
250+
this.vocabularyTreeviewService.loadMore(node.item, this.getSelectedEntryIds(), true, this.loadAllNodes);
245251
}
246252

247253
/**

src/app/shared/form/vocabulary-treeview/vocabulary-treeview.service.ts

Lines changed: 55 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Injectable } from '@angular/core';
22

3-
import { BehaviorSubject, Observable, of as observableOf } from 'rxjs';
3+
import { BehaviorSubject, EMPTY, expand, Observable, of as observableOf } from 'rxjs';
44
import { map, merge, mergeMap, scan } from 'rxjs/operators';
55
import findIndex from 'lodash/findIndex';
66

@@ -97,8 +97,9 @@ export class VocabularyTreeviewService {
9797
* @param pageInfo The {@link PageInfo} object
9898
* @param selectedItems The currently selected items
9999
* @param initValueId The entry id of the node to mark as selected, if any
100+
* @param loadAll
100101
*/
101-
initialize(options: VocabularyOptions, pageInfo: PageInfo, selectedItems: string[], initValueId?: string): void {
102+
initialize(options: VocabularyOptions, pageInfo: PageInfo, selectedItems: string[], initValueId?: string, loadAll = false): void {
102103
this.loading.next(true);
103104
this.vocabularyOptions = options;
104105
this.vocabularyName = options.name;
@@ -107,7 +108,7 @@ export class VocabularyTreeviewService {
107108
this.getNodeHierarchyById(initValueId, selectedItems)
108109
.subscribe((hierarchy: string[]) => {
109110
this.initValueHierarchy = hierarchy;
110-
this.retrieveTopNodes(pageInfo, [], selectedItems);
111+
this.retrieveTopNodes(pageInfo, [], selectedItems, loadAll);
111112
});
112113
} else {
113114
this.retrieveTopNodes(pageInfo, [], selectedItems);
@@ -137,22 +138,25 @@ export class VocabularyTreeviewService {
137138
* @param item
138139
* @param selectedItems
139140
* @param onlyFirstTime
141+
* @param loadAll
140142
*/
141-
loadMore(item: VocabularyEntryDetail, selectedItems: string[], onlyFirstTime = false) {
143+
loadMore(item: VocabularyEntryDetail, selectedItems: string[], onlyFirstTime = false, loadAll = false) {
142144
if (!this.nodeMap.has(item.otherInformation.id)) {
143145
return;
144146
}
145147
const parent: TreeviewNode = this.nodeMap.get(item.otherInformation.id)!;
146148
const children = this.nodeMap.get(item.otherInformation.id)!.children || [];
147-
this.getChildrenNodesByParent(item.otherInformation.id, parent.pageInfo).subscribe((list: PaginatedList<VocabularyEntryDetail>) => {
148-
149-
if (onlyFirstTime && parent.children!.length > 0) {
149+
this.getChildrenNodesByParent(item.otherInformation.id, parent.pageInfo, (loadAll && selectedItems.length > 0)).subscribe((list: PaginatedList<VocabularyEntryDetail>) => {
150+
if (onlyFirstTime && parent.children!.length > 0 && !loadAll) {
150151
return;
151152
}
152153

153154
const newNodes: TreeviewNode[] = list.page.map((entry) => this._generateNode(entry, selectedItems));
154155
if (newNodes.length > 0) {
155-
children.pop();
156+
if (!loadAll) {
157+
//remove load more button
158+
children.pop();
159+
}
156160
children.push(...newNodes);
157161
}
158162

@@ -162,16 +166,19 @@ export class VocabularyTreeviewService {
162166
currentPage: list.pageInfo.currentPage + 1
163167
});
164168
parent.updatePageInfo(newPageInfo);
169+
parent.childrenChange.next(children);
165170

166-
// Need a new load more node
167-
children.push(new TreeviewNode(LOAD_MORE_NODE, false, newPageInfo, item));
171+
if (!(loadAll && selectedItems.length > 0)) {
172+
// if not all loaded add a load more button
173+
children.push(new TreeviewNode(LOAD_MORE_NODE, false, newPageInfo, item));
174+
}
175+
} else {
176+
parent.childrenChange.next(children);
168177
}
169-
parent.childrenChange.next(children);
170178
this.dataChange.next(this.dataChange.value);
171179
});
172180

173181
}
174-
175182
/**
176183
* Check if any operation is pending
177184
*/
@@ -276,14 +283,36 @@ export class VocabularyTreeviewService {
276283
* Return the vocabulary entry's children
277284
* @param parentId The node id
278285
* @param pageInfo The {@link PageInfo} object
286+
* @param loadAll
287+
* @param selectedItem
279288
* @return Observable<PaginatedList<VocabularyEntryDetail>>
280289
*/
281-
private getChildrenNodesByParent(parentId: string, pageInfo: PageInfo): Observable<PaginatedList<VocabularyEntryDetail>> {
290+
private getChildrenNodesByParent(parentId: string, pageInfo: PageInfo, loadAll = false): Observable<PaginatedList<VocabularyEntryDetail>> {
282291
return this.vocabularyService.getEntryDetailChildren(parentId, this.vocabularyName, pageInfo).pipe(
283-
getFirstSucceededRemoteDataPayload()
292+
getFirstSucceededRemoteDataPayload(),
293+
).pipe(
294+
expand(res => this.getPaginatedChildren(res, parentId, loadAll))
284295
);
285296
}
286297

298+
299+
/**
300+
* Get children recursively in expand to load all children
301+
* @param res
302+
* @param parentId
303+
* @param loadAll
304+
* @private
305+
*/
306+
private getPaginatedChildren(res: PaginatedList<VocabularyEntryDetail>, parentId: string, loadAll: boolean): Observable<PaginatedList<VocabularyEntryDetail>> {
307+
if (res.pageInfo.currentPage + 1 <= res.pageInfo.totalPages && loadAll) {
308+
const newPageInfo = Object.assign({}, res.pageInfo, {currentPage: res.pageInfo.currentPage + 1});
309+
return this.vocabularyService.getEntryDetailChildren(parentId, this.vocabularyName, newPageInfo).pipe(
310+
getFirstSucceededRemoteDataPayload()
311+
);
312+
}
313+
return EMPTY;
314+
}
315+
287316
/**
288317
* Return the vocabulary entry's parent
289318
* @param entryId The entry id
@@ -310,8 +339,9 @@ export class VocabularyTreeviewService {
310339
* @param pageInfo The {@link PageInfo} object
311340
* @param nodes The top level nodes already loaded, if any
312341
* @param selectedItems The currently selected items
342+
* @param loadAll
313343
*/
314-
private retrieveTopNodes(pageInfo: PageInfo, nodes: TreeviewNode[], selectedItems: string[]): void {
344+
private retrieveTopNodes(pageInfo: PageInfo, nodes: TreeviewNode[], selectedItems: string[], loadAll = false): void {
315345
this.vocabularyService.searchTopEntries(this.vocabularyName, pageInfo).pipe(
316346
getFirstSucceededRemoteDataPayload()
317347
).subscribe((list: PaginatedList<VocabularyEntryDetail>) => {
@@ -320,13 +350,19 @@ export class VocabularyTreeviewService {
320350
nodes.push(...newNodes);
321351

322352
if ((list.pageInfo.currentPage + 1) <= list.pageInfo.totalPages) {
323-
// Need a new load more node
324353
const newPageInfo: PageInfo = Object.assign(new PageInfo(), list.pageInfo, {
325354
currentPage: list.pageInfo.currentPage + 1
326355
});
327-
const loadMoreNode = new TreeviewNode(LOAD_MORE_ROOT_NODE, false, newPageInfo);
328-
loadMoreNode.updatePageInfo(newPageInfo);
329-
nodes.push(loadMoreNode);
356+
357+
if (loadAll) {
358+
// loop over pages until we load all of them
359+
this.retrieveTopNodes(newPageInfo, nodes, selectedItems);
360+
return;
361+
} else {
362+
const loadMoreNode = new TreeviewNode(LOAD_MORE_ROOT_NODE, false, newPageInfo);
363+
loadMoreNode.updatePageInfo(newPageInfo);
364+
nodes.push(loadMoreNode);
365+
}
330366
}
331367
this.loading.next(false);
332368
// Notify the change.

0 commit comments

Comments
 (0)