mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-07-24 17:32:15 +00:00
[ADF-3763] fixed subscription for node child and invalid node id (#3991)
* [ADF-3763] fixed subscription for node child and invalid node id * [ADF-3763] removed fdescribe * [ADF-3763] added line for updating documentation
This commit is contained in:
@@ -1,10 +1,19 @@
|
|||||||
<div>TREE VIEW TEST</div>
|
<div>TREE VIEW TEST</div>
|
||||||
<mat-form-field class="example-full-width">
|
<mat-form-field class="example-full-width">
|
||||||
<input matInput placeholder="Node Id" [(ngModel)]="nodeIdSample">
|
<input matInput placeholder="Node Id"
|
||||||
|
[(ngModel)]="nodeIdSample"
|
||||||
|
(ngModelChange)="reset()">
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<span>
|
<span>
|
||||||
CLICKED NODE: {{clickedNodeName}}
|
CLICKED NODE: {{clickedNodeName}}
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<adf-tree-view-list [nodeId]="nodeIdSample" (nodeClicked)="onClick($event)">
|
<adf-tree-view-list *ngIf="!errorMessage; else erroOccurred"
|
||||||
|
[nodeId]="nodeIdSample"
|
||||||
|
(nodeClicked)="onClick($event)"
|
||||||
|
(error)="onErrorOccurred($event)">
|
||||||
</adf-tree-view-list>
|
</adf-tree-view-list>
|
||||||
|
<ng-template #erroOccurred>
|
||||||
|
<span>An Error Occurred </span>
|
||||||
|
<span>{{errorMessage}}</span>
|
||||||
|
</ng-template>
|
||||||
|
@@ -25,10 +25,21 @@ import { Component } from '@angular/core';
|
|||||||
export class TreeViewSampleComponent {
|
export class TreeViewSampleComponent {
|
||||||
|
|
||||||
clickedNodeName: string = '';
|
clickedNodeName: string = '';
|
||||||
|
errorMessage = '';
|
||||||
|
|
||||||
nodeIdSample: string = '-my-';
|
nodeIdSample: string = '-my-';
|
||||||
|
|
||||||
onClick(node) {
|
onClick(node) {
|
||||||
this.clickedNodeName = node.entry.name;
|
this.clickedNodeName = node.entry.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reset() {
|
||||||
|
this.clickedNodeName = '';
|
||||||
|
this.errorMessage = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
onErrorOccurred(error) {
|
||||||
|
this.clickedNodeName = '';
|
||||||
|
this.errorMessage = error;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -30,4 +30,5 @@ Shows the folder and subfolders of a node as a tree view.
|
|||||||
|
|
||||||
| Name | Type | Description |
|
| Name | Type | Description |
|
||||||
| ---- | ---- | ----------- |
|
| ---- | ---- | ----------- |
|
||||||
|
| error | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<any>` | Emitted when an invalid node id is given. |
|
||||||
| nodeClicked | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<`[`NodeEntry`](https://github.com/Alfresco/alfresco-js-api/blob/master/src/alfresco-core-rest-api/docs/NodeEntry.md)`>` | Emitted when a node in the tree view is clicked. |
|
| nodeClicked | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<`[`NodeEntry`](https://github.com/Alfresco/alfresco-js-api/blob/master/src/alfresco-core-rest-api/docs/NodeEntry.md)`>` | Emitted when a node in the tree view is clicked. |
|
||||||
|
@@ -1,9 +1,12 @@
|
|||||||
<mat-tree class="adf-tree-view-main" [dataSource]="dataSource" [treeControl]="treeControl" *ngIf="nodeId; else missingNodeId">
|
<mat-tree class="adf-tree-view-main" [dataSource]="dataSource"
|
||||||
<mat-tree-node class="adf-tree-view-node" *matTreeNodeDef="let treeNode" id="{{treeNode.name + '-tree-node'}}"
|
[treeControl]="treeControl" *ngIf="nodeId; else missingNodeId">
|
||||||
|
<mat-tree-node class="adf-tree-view-node"
|
||||||
|
*matTreeNodeDef="let treeNode" id="{{treeNode.name + '-tree-node'}}"
|
||||||
matTreeNodePadding [matTreeNodePaddingIndent]="15">
|
matTreeNodePadding [matTreeNodePaddingIndent]="15">
|
||||||
{{treeNode.name}}
|
{{treeNode.name}}
|
||||||
</mat-tree-node>
|
</mat-tree-node>
|
||||||
<mat-tree-node class="adf-tree-view-node" id="{{treeNode.name + '-tree-child-node'}}" *matTreeNodeDef="let treeNode; when: hasChild"
|
<mat-tree-node class="adf-tree-view-node"
|
||||||
|
id="{{treeNode.name + '-tree-child-node'}}" *matTreeNodeDef="let treeNode; when: hasChild"
|
||||||
matTreeNodePadding [matTreeNodePaddingIndent]="15">
|
matTreeNodePadding [matTreeNodePaddingIndent]="15">
|
||||||
<button id="{{'button-'+treeNode.name}}" (click)="onNodeClicked(treeNode.node)"
|
<button id="{{'button-'+treeNode.name}}" (click)="onNodeClicked(treeNode.node)"
|
||||||
mat-icon-button [attr.aria-label]="'toggle ' + treeNode.filename" matTreeNodeToggle>
|
mat-icon-button [attr.aria-label]="'toggle ' + treeNode.filename" matTreeNodeToggle>
|
||||||
|
@@ -20,9 +20,10 @@ import { setupTestBed } from '@alfresco/adf-core';
|
|||||||
import { TreeViewComponent } from './tree-view.component';
|
import { TreeViewComponent } from './tree-view.component';
|
||||||
import { ContentTestingModule } from '../../testing/content.testing.module';
|
import { ContentTestingModule } from '../../testing/content.testing.module';
|
||||||
import { TreeViewService } from '../services/tree-view.service';
|
import { TreeViewService } from '../services/tree-view.service';
|
||||||
import { of } from 'rxjs';
|
import { of, throwError } from 'rxjs';
|
||||||
import { TreeBaseNode } from '../models/tree-view.model';
|
import { TreeBaseNode } from '../models/tree-view.model';
|
||||||
import { NodeEntry } from 'alfresco-js-api';
|
import { NodeEntry } from 'alfresco-js-api';
|
||||||
|
import { SimpleChange } from '@angular/core';
|
||||||
|
|
||||||
describe('TreeViewComponent', () => {
|
describe('TreeViewComponent', () => {
|
||||||
|
|
||||||
@@ -73,6 +74,8 @@ describe('TreeViewComponent', () => {
|
|||||||
component = fixture.componentInstance;
|
component = fixture.componentInstance;
|
||||||
spyOn(treeService, 'getTreeNodes').and.callFake((nodeId) => returnRootOrChildrenNode(nodeId));
|
spyOn(treeService, 'getTreeNodes').and.callFake((nodeId) => returnRootOrChildrenNode(nodeId));
|
||||||
component.nodeId = '9999999';
|
component.nodeId = '9999999';
|
||||||
|
const changeNodeId = new SimpleChange(null, '9999999', true);
|
||||||
|
component.ngOnChanges({ 'nodeId': changeNodeId });
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@@ -95,6 +98,24 @@ describe('TreeViewComponent', () => {
|
|||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
it('should show only the correct subfolders when the nodeId is changed', async(() => {
|
||||||
|
component.nodeId = 'fake-second-id';
|
||||||
|
const changeNodeId = new SimpleChange('9999999', 'fake-second-id', true);
|
||||||
|
component.ngOnChanges({ 'nodeId': changeNodeId });
|
||||||
|
fixture.detectChanges();
|
||||||
|
fixture.whenStable().then(() => {
|
||||||
|
let rootFolderButton: HTMLButtonElement = <HTMLButtonElement> element.querySelector('#button-fake-next-child-name');
|
||||||
|
expect(rootFolderButton).not.toBeNull();
|
||||||
|
rootFolderButton.click();
|
||||||
|
fixture.detectChanges();
|
||||||
|
fixture.whenStable().then(() => {
|
||||||
|
expect(element.querySelector('#fake-child-name-tree-child-node')).not.toBeNull();
|
||||||
|
expect(element.querySelector('#fake-second-name-tree-child-node')).not.toBeNull();
|
||||||
|
expect(element.querySelectorAll('mat-tree-node').length).toBe(4);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
it('should throw a nodeClicked event when a node is clicked', (done) => {
|
it('should throw a nodeClicked event when a node is clicked', (done) => {
|
||||||
component.nodeClicked.subscribe((nodeClicked: NodeEntry) => {
|
component.nodeClicked.subscribe((nodeClicked: NodeEntry) => {
|
||||||
expect(nodeClicked).toBeDefined();
|
expect(nodeClicked).toBeDefined();
|
||||||
@@ -178,4 +199,28 @@ describe('TreeViewComponent', () => {
|
|||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('When invalid nodeId is given', () => {
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
|
fixture = TestBed.createComponent(TreeViewComponent);
|
||||||
|
treeService = TestBed.get(TreeViewService);
|
||||||
|
spyOn(treeService, 'getTreeNodes').and.callFake((nodeId) => throwError('Invalid Node Id'));
|
||||||
|
fixture.componentInstance.nodeId = 'Poopoovic';
|
||||||
|
}));
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
fixture.destroy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should raise an error event when invalid nodeId is provided', (done) => {
|
||||||
|
fixture.componentInstance.error.subscribe((error) => {
|
||||||
|
expect(error).toBe('Invalid Node Id');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
const changeNodeId = new SimpleChange(null, 'Poopoovic', true);
|
||||||
|
fixture.componentInstance.ngOnChanges({ 'nodeId': changeNodeId });
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@@ -16,7 +16,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { FlatTreeControl } from '@angular/cdk/tree';
|
import { FlatTreeControl } from '@angular/cdk/tree';
|
||||||
import { Component, Input, OnInit, OnChanges, SimpleChanges, Output, EventEmitter } from '@angular/core';
|
import { Component, Input, OnChanges, SimpleChanges, Output, EventEmitter } from '@angular/core';
|
||||||
import { TreeBaseNode } from '../models/tree-view.model';
|
import { TreeBaseNode } from '../models/tree-view.model';
|
||||||
import { TreeViewDataSource } from '../data/tree-view-datasource';
|
import { TreeViewDataSource } from '../data/tree-view-datasource';
|
||||||
import { TreeViewService } from '../services/tree-view.service';
|
import { TreeViewService } from '../services/tree-view.service';
|
||||||
@@ -28,7 +28,7 @@ import { NodeEntry } from 'alfresco-js-api';
|
|||||||
styleUrls: ['tree-view.component.scss']
|
styleUrls: ['tree-view.component.scss']
|
||||||
})
|
})
|
||||||
|
|
||||||
export class TreeViewComponent implements OnInit, OnChanges {
|
export class TreeViewComponent implements OnChanges {
|
||||||
|
|
||||||
/** Identifier of the node to display. */
|
/** Identifier of the node to display. */
|
||||||
@Input()
|
@Input()
|
||||||
@@ -38,6 +38,10 @@ export class TreeViewComponent implements OnInit, OnChanges {
|
|||||||
@Output()
|
@Output()
|
||||||
nodeClicked: EventEmitter<NodeEntry> = new EventEmitter();
|
nodeClicked: EventEmitter<NodeEntry> = new EventEmitter();
|
||||||
|
|
||||||
|
/** Emitted when an invalid node id is given. */
|
||||||
|
@Output()
|
||||||
|
error: EventEmitter<any> = new EventEmitter();
|
||||||
|
|
||||||
treeControl: FlatTreeControl<TreeBaseNode>;
|
treeControl: FlatTreeControl<TreeBaseNode>;
|
||||||
dataSource: TreeViewDataSource;
|
dataSource: TreeViewDataSource;
|
||||||
|
|
||||||
@@ -46,16 +50,12 @@ export class TreeViewComponent implements OnInit, OnChanges {
|
|||||||
this.dataSource = new TreeViewDataSource(this.treeControl, this.treeViewService);
|
this.dataSource = new TreeViewDataSource(this.treeControl, this.treeViewService);
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
|
||||||
if (this.nodeId) {
|
|
||||||
this.loadTreeNode();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ngOnChanges(changes: SimpleChanges) {
|
ngOnChanges(changes: SimpleChanges) {
|
||||||
if (changes['nodeId'].currentValue &&
|
if (changes['nodeId'] && changes['nodeId'].currentValue &&
|
||||||
changes['nodeId'].currentValue !== changes['nodeId'].previousValue) {
|
changes['nodeId'].currentValue !== changes['nodeId'].previousValue) {
|
||||||
this.loadTreeNode();
|
this.loadTreeNode();
|
||||||
|
} else {
|
||||||
|
this.dataSource.data = [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,6 +74,8 @@ export class TreeViewComponent implements OnInit, OnChanges {
|
|||||||
.subscribe(
|
.subscribe(
|
||||||
(treeNode: TreeBaseNode[]) => {
|
(treeNode: TreeBaseNode[]) => {
|
||||||
this.dataSource.data = treeNode;
|
this.dataSource.data = treeNode;
|
||||||
});
|
},
|
||||||
|
(error) => this.error.emit(error)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -28,6 +28,8 @@ export class TreeViewDataSource {
|
|||||||
|
|
||||||
treeNodes: TreeBaseNode[];
|
treeNodes: TreeBaseNode[];
|
||||||
dataChange = new BehaviorSubject<TreeBaseNode[]>([]);
|
dataChange = new BehaviorSubject<TreeBaseNode[]>([]);
|
||||||
|
childrenSubscription = null;
|
||||||
|
changeSubscription = null;
|
||||||
|
|
||||||
get data(): TreeBaseNode[] {
|
get data(): TreeBaseNode[] {
|
||||||
return this.treeNodes;
|
return this.treeNodes;
|
||||||
@@ -44,7 +46,7 @@ export class TreeViewDataSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
connect(collectionViewer: CollectionViewer): Observable<TreeBaseNode[]> {
|
connect(collectionViewer: CollectionViewer): Observable<TreeBaseNode[]> {
|
||||||
this.treeControl.expansionModel.onChange!.subscribe(change => {
|
this.changeSubscription = this.treeControl.expansionModel.onChange.subscribe(change => {
|
||||||
if ((change as SelectionChange<TreeBaseNode>).added &&
|
if ((change as SelectionChange<TreeBaseNode>).added &&
|
||||||
(change as SelectionChange<TreeBaseNode>).added.length > 0) {
|
(change as SelectionChange<TreeBaseNode>).added.length > 0) {
|
||||||
this.expandTreeNodes(change as SelectionChange<TreeBaseNode>);
|
this.expandTreeNodes(change as SelectionChange<TreeBaseNode>);
|
||||||
@@ -55,6 +57,15 @@ export class TreeViewDataSource {
|
|||||||
return merge(collectionViewer.viewChange, this.dataChange).pipe(map(() => this.data));
|
return merge(collectionViewer.viewChange, this.dataChange).pipe(map(() => this.data));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
disconnect() {
|
||||||
|
if (this.childrenSubscription) {
|
||||||
|
this.childrenSubscription.unsubscribe();
|
||||||
|
}
|
||||||
|
if (this.changeSubscription) {
|
||||||
|
this.changeSubscription.unsubscribe();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private expandTreeNodes(change: SelectionChange<TreeBaseNode>) {
|
private expandTreeNodes(change: SelectionChange<TreeBaseNode>) {
|
||||||
change.added.forEach(node => this.expandNode(node));
|
change.added.forEach(node => this.expandNode(node));
|
||||||
}
|
}
|
||||||
@@ -64,7 +75,8 @@ export class TreeViewDataSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private expandNode(node: TreeBaseNode) {
|
private expandNode(node: TreeBaseNode) {
|
||||||
this.treeViewService.getTreeNodes(node.nodeId).subscribe((children) => {
|
this.childrenSubscription = this.treeViewService.getTreeNodes(node.nodeId)
|
||||||
|
.subscribe((children) => {
|
||||||
const index = this.data.indexOf(node);
|
const index = this.data.indexOf(node);
|
||||||
if (!children || index < 0) {
|
if (!children || index < 0) {
|
||||||
node.expandable = false;
|
node.expandable = false;
|
||||||
|
Reference in New Issue
Block a user