Skip to content

fix(tree): allow readonly arrays in getChildren return type #17825

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/cdk/tree/control/base-tree-control.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
* found in the LICENSE file at https://angular.io/license
*/
import {SelectionModel} from '@angular/cdk/collections';
import {Observable} from 'rxjs';
import {TreeControl} from './tree-control';
import {GetChildrenFn} from './types';

/** Base tree control. It has basic toggle/expand/collapse operations on a single data node. */
export abstract class BaseTreeControl<T, K = T> implements TreeControl<T, K> {
Expand All @@ -19,7 +19,7 @@ export abstract class BaseTreeControl<T, K = T> implements TreeControl<T, K> {
abstract expandAll(): void;

/** Saved data node for `expandAll` action. */
dataNodes: T[];
dataNodes: T[] | ReadonlyArray<T>;

/** A selection model with multi-selection to track expansion status. */
expansionModel: SelectionModel<K> = new SelectionModel<K>(true);
Expand All @@ -42,7 +42,7 @@ export abstract class BaseTreeControl<T, K = T> implements TreeControl<T, K> {
isExpandable: (dataNode: T) => boolean;

/** Gets a stream that emits whenever the given data node's children change. */
getChildren: (dataNode: T) => (Observable<T[]> | T[] | undefined | null);
getChildren: GetChildrenFn<T>;

/** Toggles one single data node's expanded/collapsed state. */
toggle(dataNode: T): void {
Expand Down
2 changes: 1 addition & 1 deletion src/cdk/tree/control/flat-tree-control.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,6 @@ export class FlatTreeControl<T, K = T> extends BaseTreeControl<T, K> {
* data nodes of the tree.
*/
expandAll(): void {
this.expansionModel.select(...this.dataNodes.map(node => this._trackByValue(node)));
this.expansionModel.select(...(this.dataNodes as T[]).map(node => this._trackByValue(node)));
}
}
7 changes: 4 additions & 3 deletions src/cdk/tree/control/nested-tree-control.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {Observable, isObservable} from 'rxjs';
import {isObservable} from 'rxjs';
import {take, filter} from 'rxjs/operators';
import {BaseTreeControl} from './base-tree-control';
import {GetChildrenFn} from './types';

/** Optional set of configuration that can be provided to the NestedTreeControl. */
export interface NestedTreeControlOptions<T, K> {
Expand All @@ -18,7 +19,7 @@ export interface NestedTreeControlOptions<T, K> {
export class NestedTreeControl<T, K = T> extends BaseTreeControl<T, K> {
/** Construct with nested tree function getChildren. */
constructor(
public getChildren: (dataNode: T) => (Observable<T[]>| T[] | undefined | null),
public getChildren: GetChildrenFn<T>,
public options?: NestedTreeControlOptions<T, K>) {
super();

Expand All @@ -35,7 +36,7 @@ export class NestedTreeControl<T, K = T> extends BaseTreeControl<T, K> {
*/
expandAll(): void {
this.expansionModel.clear();
const allNodes = this.dataNodes.reduce((accumulator: T[], dataNode) =>
const allNodes = (this.dataNodes as ReadonlyArray<T>).reduce((accumulator: T[], dataNode) =>
[...accumulator, ...this.getDescendants(dataNode), dataNode], []);
this.expansionModel.select(...allNodes.map(node => this._trackByValue(node)));
}
Expand Down
6 changes: 3 additions & 3 deletions src/cdk/tree/control/tree-control.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
import {SelectionModel} from '@angular/cdk/collections';
import {Observable} from 'rxjs';
import {GetChildrenFn} from './types';

/**
* Tree control interface. User can implement TreeControl to expand/collapse dataNodes in the tree.
Expand All @@ -15,7 +15,7 @@ import {Observable} from 'rxjs';
*/
export interface TreeControl<T, K = T> {
/** The saved tree nodes data for `expandAll` action. */
dataNodes: T[];
dataNodes: T[] | ReadonlyArray<T>;

/** The expansion model */
expansionModel: SelectionModel<K>;
Expand Down Expand Up @@ -60,5 +60,5 @@ export interface TreeControl<T, K = T> {
readonly isExpandable: (dataNode: T) => boolean;

/** Gets a stream that emits whenever the given data node's children change. */
readonly getChildren: (dataNode: T) => Observable<T[]> | T[] | undefined | null;
readonly getChildren: GetChildrenFn<T>;
}
13 changes: 13 additions & 0 deletions src/cdk/tree/control/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/

import {Observable} from 'rxjs';

/** Function that can be used to get the children of a tree node. */
export type GetChildrenFn<T> = (node: T) =>
Observable<T[] | ReadonlyArray<T>> | T[] | ReadonlyArray<T> | undefined | null;
4 changes: 2 additions & 2 deletions src/cdk/tree/nested-node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export class CdkNestedTreeNode<T> extends CdkTreeNode<T> implements AfterContent
private _dataDiffer: IterableDiffer<T>;

/** The children data dataNodes of current node. They will be placed in `CdkTreeNodeOutlet`. */
protected _children: T[];
protected _children: T[] | ReadonlyArray<T>;

/** The children node placeholder. */
@ContentChildren(CdkTreeNodeOutlet, {
Expand Down Expand Up @@ -84,7 +84,7 @@ export class CdkNestedTreeNode<T> extends CdkTreeNode<T> implements AfterContent
}

/** Add children dataNodes to the NodeOutlet */
protected updateChildrenNodes(children?: T[]): void {
protected updateChildrenNodes(children?: T[] | ReadonlyArray<T>): void {
const outlet = this._getNodeOutlet();
if (children) {
this._children = children;
Expand Down
1 change: 1 addition & 0 deletions src/cdk/tree/public-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export * from './control/base-tree-control';
export * from './control/flat-tree-control';
export * from './control/nested-tree-control';
export * from './control/tree-control';
export * from './control/types';
export * from './nested-node';
export * from './node';
export * from './padding';
Expand Down
2 changes: 1 addition & 1 deletion src/cdk/tree/tree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -381,7 +381,7 @@ export class CdkTreeNode<T> implements FocusableOption, OnDestroy {
}
}

protected _setRoleFromChildren(children: T[]) {
protected _setRoleFromChildren(children: T[] | ReadonlyArray<T>) {
this.role = children && children.length ? 'group' : 'treeitem';
}
}
7 changes: 3 additions & 4 deletions src/material/tree/data-source/flat-data-source.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
*/

import {CollectionViewer, DataSource} from '@angular/cdk/collections';
import {FlatTreeControl, TreeControl} from '@angular/cdk/tree';
import {FlatTreeControl, TreeControl, GetChildrenFn} from '@angular/cdk/tree';
import {BehaviorSubject, merge, Observable} from 'rxjs';
import {map, take} from 'rxjs/operators';

Expand Down Expand Up @@ -50,8 +50,7 @@ export class MatTreeFlattener<T, F, K = F> {
constructor(public transformFunction: (node: T, level: number) => F,
public getLevel: (node: F) => number,
public isExpandable: (node: F) => boolean,
public getChildren: (node: T) =>
Observable<T[]> | T[] | undefined | null) {}
public getChildren: GetChildrenFn<T>) {}

_flattenNode(node: T, level: number,
resultNodes: F[], parentMap: boolean[]): F[] {
Expand All @@ -64,7 +63,7 @@ export class MatTreeFlattener<T, F, K = F> {
if (Array.isArray(childrenNodes)) {
this._flattenChildren(childrenNodes, level, resultNodes, parentMap);
} else {
childrenNodes.pipe(take(1)).subscribe(children => {
(childrenNodes as Observable<T[]>).pipe(take(1)).subscribe(children => {
this._flattenChildren(children, level, resultNodes, parentMap);
});
}
Expand Down
20 changes: 11 additions & 9 deletions tools/public_api_guard/cdk/tree.d.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
export declare abstract class BaseTreeControl<T, K = T> implements TreeControl<T, K> {
dataNodes: T[];
dataNodes: T[] | ReadonlyArray<T>;
expansionModel: SelectionModel<K>;
getChildren: (dataNode: T) => (Observable<T[]> | T[] | undefined | null);
getChildren: GetChildrenFn<T>;
getLevel: (dataNode: T) => number;
isExpandable: (dataNode: T) => boolean;
trackBy?: (dataNode: T) => K;
Expand All @@ -21,7 +21,7 @@ export declare abstract class BaseTreeControl<T, K = T> implements TreeControl<T
export declare const CDK_TREE_NODE_OUTLET_NODE: InjectionToken<{}>;

export declare class CdkNestedTreeNode<T> extends CdkTreeNode<T> implements AfterContentInit, OnDestroy {
protected _children: T[];
protected _children: T[] | ReadonlyArray<T>;
protected _differs: IterableDiffers;
protected _elementRef: ElementRef<HTMLElement>;
protected _tree: CdkTree<T>;
Expand All @@ -30,7 +30,7 @@ export declare class CdkNestedTreeNode<T> extends CdkTreeNode<T> implements Afte
protected _clear(): void;
ngAfterContentInit(): void;
ngOnDestroy(): void;
protected updateChildrenNodes(children?: T[]): void;
protected updateChildrenNodes(children?: T[] | ReadonlyArray<T>): void;
static ɵdir: i0.ɵɵDirectiveDefWithMeta<CdkNestedTreeNode<any>, "cdk-nested-tree-node", ["cdkNestedTreeNode"], {}, {}, ["nodeOutlet"]>;
static ɵfac: i0.ɵɵFactoryDef<CdkNestedTreeNode<any>, never>;
}
Expand Down Expand Up @@ -74,7 +74,7 @@ export declare class CdkTreeNode<T> implements FocusableOption, OnDestroy {
get level(): number;
role: 'treeitem' | 'group';
constructor(_elementRef: ElementRef<HTMLElement>, _tree: CdkTree<T>);
protected _setRoleFromChildren(children: T[]): void;
protected _setRoleFromChildren(children: T[] | ReadonlyArray<T>): void;
protected _setRoleFromData(): void;
focus(): void;
ngOnDestroy(): void;
Expand Down Expand Up @@ -151,6 +151,8 @@ export interface FlatTreeControlOptions<T, K> {
trackBy?: (dataNode: T) => K;
}

export declare type GetChildrenFn<T> = (node: T) => Observable<T[] | ReadonlyArray<T>> | T[] | ReadonlyArray<T> | undefined | null;

export declare function getTreeControlFunctionsMissingError(): Error;

export declare function getTreeControlMissingError(): Error;
Expand All @@ -162,9 +164,9 @@ export declare function getTreeMultipleDefaultNodeDefsError(): Error;
export declare function getTreeNoValidDataSourceError(): Error;

export declare class NestedTreeControl<T, K = T> extends BaseTreeControl<T, K> {
getChildren: (dataNode: T) => (Observable<T[]> | T[] | undefined | null);
getChildren: GetChildrenFn<T>;
options?: NestedTreeControlOptions<T, K> | undefined;
constructor(getChildren: (dataNode: T) => (Observable<T[]> | T[] | undefined | null), options?: NestedTreeControlOptions<T, K> | undefined);
constructor(getChildren: GetChildrenFn<T>, options?: NestedTreeControlOptions<T, K> | undefined);
protected _getDescendants(descendants: T[], dataNode: T): void;
expandAll(): void;
getDescendants(dataNode: T): T[];
Expand All @@ -175,9 +177,9 @@ export interface NestedTreeControlOptions<T, K> {
}

export interface TreeControl<T, K = T> {
dataNodes: T[];
dataNodes: T[] | ReadonlyArray<T>;
expansionModel: SelectionModel<K>;
readonly getChildren: (dataNode: T) => Observable<T[]> | T[] | undefined | null;
readonly getChildren: GetChildrenFn<T>;
readonly getLevel: (dataNode: T) => number;
readonly isExpandable: (dataNode: T) => boolean;
collapse(dataNode: T): void;
Expand Down
4 changes: 2 additions & 2 deletions tools/public_api_guard/material/tree.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,11 @@ export declare class MatTreeFlatDataSource<T, F, K = F> extends DataSource<F> {
}

export declare class MatTreeFlattener<T, F, K = F> {
getChildren: (node: T) => Observable<T[]> | T[] | undefined | null;
getChildren: GetChildrenFn<T>;
getLevel: (node: F) => number;
isExpandable: (node: F) => boolean;
transformFunction: (node: T, level: number) => F;
constructor(transformFunction: (node: T, level: number) => F, getLevel: (node: F) => number, isExpandable: (node: F) => boolean, getChildren: (node: T) => Observable<T[]> | T[] | undefined | null);
constructor(transformFunction: (node: T, level: number) => F, getLevel: (node: F) => number, isExpandable: (node: F) => boolean, getChildren: GetChildrenFn<T>);
_flattenChildren(children: T[], level: number, resultNodes: F[], parentMap: boolean[]): void;
_flattenNode(node: T, level: number, resultNodes: F[], parentMap: boolean[]): F[];
expandFlattenedNodes(nodes: F[], treeControl: TreeControl<F, K>): F[];
Expand Down