Skip to content

Conversation

tinayuangao
Copy link
Contributor

@tinayuangao tinayuangao commented Oct 23, 2017

An initial version of cdk-tree

For #3175

@googlebot googlebot added the cla: yes PR author has agreed to Google's Contributor License Agreement label Oct 23, 2017
@@ -0,0 +1,18 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The license changed recently; it's Google LLC now


expandFlattenedNodes(nodes: T[], expansionModel: SelectionModel<T>): T[];

nodeDecedents(node: T, nodes: T[], onlyExpandable: boolean);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add JsDoc description for these methods?



/**
* Nested node, add children to `cdkNodePlaceholder` in template.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clarify that this is a child of <cdk-tree> and what is means to be a "nested node"? I'm also not sure exactly what "add children to `cdkNodePlaceholder` in template." means

protected _childrenSubscription: Subscription;

/** Subscribes to node placeholder changes. */
protected _placeholderSubscription: Subscription;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One pattern we've been using more lately is to create a subject like _destroyed and then use takeUntil(this._destroyed) to avoid needing to manually keep track of the subscription and unsubscribe

@ContentChildren(CdkNodePlaceholder) nodePlaceholder: QueryList<CdkNodePlaceholder>;

/** The Children nodes data. */
protected _children: T[];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not very clear on what this represents exactly


/** Expands a subtree rooted at given `node` recursively. */
expandDecedents(node: T) {
let decedents = this.getDecedents(node);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prefer const (here and elsewhere)

*/
expandAll() {
this.expansionModel.clear();
this.nodes.forEach((node) => this._expandDecedents(node));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: don't need parens for a single argument with inferred type (here and elsewhere)

if (children) {
children.forEach((child) => {
this.collapseDecedents(child)
});
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't need to use braces here

children.forEach(child => this.collapseDecedents(child));

(similar elsewhere)


/** Interface for data in flat tree. Tree users should implement this interface to use CdkTree. */
export interface FlatNode {
level: number;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we do a getLevel method instead of a property? It might be annoying if someone has a level property in their data that means something else. (Same for expandable -> isExpandable).

I also wonder if there's a way to could express this in the template (similar to when) instead of requiring an interface, but I forget if we already explored that option

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We didn't explore that option.

I can try to express it in the template, but TreeControl is also using that to expand/collapse subtrees/the whole tree.

If we want to express this in the template, we can also pass that info to TreeControl, or put getLevel getChildren and isExpandable functions in TreeControl and let other components use functions in TreeControl.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now moved getLevel isExpandable and getChildren to TreeControl. Removed NestedNode and FlatNode types and users can use any type of data.

SimpleCdkTreeApp,
// DynamicDataSourceCdkTreeApp,
// NodeContextCdkTreeApp,
// WhenNodeCdkTreeApp
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add TODO: in front of each of these? That will change them from commented-out-code to just comments

@CaerusKaru CaerusKaru mentioned this pull request Oct 24, 2017
@tinayuangao
Copy link
Contributor Author

Comments addressed. Please take a look. Thanks!

@tinayuangao tinayuangao force-pushed the cdk-tree branch 4 times, most recently from cd453e3 to 0267610 Compare October 25, 2017 23:44
Copy link
Member

@jelbourn jelbourn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some quick comments before I I have to run

*/
export interface TreeAdapter<T> {
/** Flatten structured data to an array of data. */
flattenNodes( structuredData: any[]): T[];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extra space

* Put node descendents of node in array.
* If `onlyExpandable` is true, then only process expandable descendents.
*/
nodeDecedents(node: T, nodes: T[], onlyExpandable: boolean);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Decedents" -> "Descendants"
(here and elsewhere)

@@ -0,0 +1,28 @@
/**
* @license
* Copyright Google LLC. All Rights Reserved.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extra . after LLC

nodes: T[];

/** Expansion info: the changes */
expandChange = new BehaviorSubject<T[]>([]);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe expansionChange? @andrewseguin thoughts?

}

/** Whether a given node is expanded or not. Returns true if the node is expanded. */
expanded(node: T) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isExpanded?

/** The tree node data */
@Input('cdkTreeNode')
set data(v: T) {
this._data = v;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Break the content of this setter into a separate function?

}
}
get data(): T { return this._data; }
_data: T;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make this private?

_data: T;

/** The offset top of the element. Used by CdkTree to decide the order of the nodes. [Focus] */
private get offsetTop() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This this is private, make it a method?

return this._dir && this._dir.value === 'rtl' ? this._paddingIndent() : null;
}

constructor(private _treeNode: CdkTreeNode<T>,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move constructor above methods and below properties


constructor(private _treeNode: CdkTreeNode<T>,
private _tree: CdkTree<T>,
@Optional() private _dir: Directionality) {}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably want to have dir.change as well

})
export class CdkNodeTrigger<T> {
/** Whether expand/collapse the node recursively. */
@Input('cdkNodeTriggerRecursive') recursive: boolean = true;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

coerceBooleanProperty?

* Node trigger to expand/collapse the node.
*/
@Directive({
selector: '[cdkNodeTrigger]',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cdkNodeTrigger doesn't seem quite specific enough. Maybe cdkTreeNodeToggle?

import {CdkTree} from './tree';


describe('CdkTree', () => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In a follow-up PR, it would be good to explore creating a syntax-sugar way of testing tree content. The table, for example, has this:

      expectTableToMatchContent(tableElement, [
        ['Column A', 'Column B', 'Column C'],
        ['a_1', 'b_1', 'c_1'],
        ['a_2', 'b_2', 'c_2'],
        ['a_3', 'b_3', 'c_3'],
      ]);

For the tree, we'd need to capture level and expansion state

import {CdkNodeDef, CdkTreeNode} from './node';
import {CdkNestedTreeNode} from './nested-node';

const EXPORTED_DECLARATIONS = [
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe just call this TREE_DIRECTIVES?

@tinayuangao tinayuangao force-pushed the cdk-tree branch 2 times, most recently from bd7b0c0 to 2df887c Compare October 26, 2017 17:00
expansionModel: SelectionModel<T> = new SelectionModel<T>(true);

/** Toggles one single node. Expands a collapsed node or collapse an expanded node. */
toggle(node: T) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All of these public methods need return types. Same goes for the other files.

/** Expands one single node. */
expand(node: T) {
this.expansionModel.select(node);
this.expansionChange.next(this.expansionModel.selected);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should be able to replace the expansionChange event with the onChange from the SelectionModel.

*/
expandAll() {
this.expansionModel.clear();
this.nodes.forEach((node) => this._expandDescendants(node));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: you don't need the parentheses around node.

children.forEach((child: T) => this._getDescendants(descendants, child));
}
});
subscription.unsubscribe();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than unsubscribing manually here, you could use the first operators instead.

if (!this._tree.treeControl.getChildren) {
throw getTreeControlFunctionsMissingError();
}
takeUntil.call(this._tree.treeControl.getChildren(this._data), this._destroyed)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this subscription is set up by the setter, shouldn't it unsubscribe from any previous subscriptions? Otherwise you could end up with multiple subscriptions if the data is set multiple times.

}

/** The offset top of the element. Used by CdkTree to decide the order of the nodes. [Focus] */
private getOffsetTop() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see this method being used anywhere, is it still relevant?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed.


ngAfterViewInit() {
// For key traversal in correct order
this.items.changes.subscribe(items => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems like you're never unsubscribing from this one and I'm not sure whether Angular will complete the stream on destroy.

this.orderedNodes.reset(nodes);

const activeItem = this._keyManager ? this._keyManager.activeItem : null;
this._keyManager = new FocusKeyManager(this.orderedNodes);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since you're mutating the same QueryList, you shouldn't need to re-create the key manager every time the items change. You may have to reset the active index though.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reset it because the order of the items in the QueryList is wrong. For example:

  • node 1
  • node 2
    After expanded node 1, it becomes
  • node 1
    ---- node 3
    ---- node 4
    -node 2
    in item list, and UP_ARROW and DOWN_ARROW will jump from one node to another.
    Resetting the nodes make it become
  • node 1
    ---- node 2
    ---- node 3
  • node 4
    in key manager.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed key manager related part.

if (event.keyCode == UP_ARROW) {
this._keyManager.setPreviousItemActive();
} else if (event.keyCode == DOWN_ARROW) {
this._keyManager.setNextItemActive();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The UP_ARROW and DOWN_ARROW behavior should be handled by the key manager already.

@tinayuangao tinayuangao force-pushed the cdk-tree branch 2 times, most recently from 8918a41 to 437566f Compare October 27, 2017 22:08
@tinayuangao
Copy link
Contributor Author

  • Added tests for flat-tree-control and nested-tree-control.
  • Removed cdkTreeNode input from CdkTreeNode and put the data through static variable.
  • Removed key manager related part.

Please take a look. Thanks for review!

Copy link
Member

@crisbeto crisbeto left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, a few nits left.

this._addChildrenNodes();
});
takeUntil.call(this.nodeOutlet.changes, this._destroyed)
.subscribe((_) => this._addChildrenNodes());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The _ param here is unnecessary. We may have a lint rule for unused parameters that would complain about this.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like this is still here

*/
when: (nodeData: T, index: number) => boolean;

/** @docs-private */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should be able to set this on the directive doc, rather than the constructor.

}

/** The left padding indent value for the tree node. */
paddingIndentLeft(): string|null {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than having two properties and bindings for left and right, you could set the padding-left/padding-right instead. E.g.:

setPadding() {
  const padding = this._paddingIndent();
  const paddingProp = this._dir && this._dir.value === 'rtl' ? 'padding-right' : 'padding-left';
  
  this._renderer.setStyle(this._element.nativeElement, paddingProp, padding);
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated padding.ts. Now set the properties and listen to dir.change.

@googlebot
Copy link

So there's good news and bad news.

👍 The good news is that everyone that needs to sign a CLA (the pull request submitter and all commit authors) have done so. Everything is all good there.

😕 The bad news is that it appears that one or more commits were authored by someone other than the pull request submitter. We need to confirm that they're okay with their commits being contributed to this project. Please have them confirm that here in the pull request.

Note to project maintainer: This is a terminal state, meaning the cla/google commit status will not change from this State. It's up to you to confirm consent of the commit author(s) and merge this pull request when appropriate.

@googlebot googlebot added cla: no PR author must sign Google's Contributor License Agreement: https://opensource.google.com/docs/cla and removed cla: yes PR author has agreed to Google's Contributor License Agreement labels Oct 30, 2017
@tinayuangao tinayuangao added the cla: yes PR author has agreed to Google's Contributor License Agreement label Oct 30, 2017
@tinayuangao
Copy link
Contributor Author

Comments addressed. Please take another look. Thanks!

@tinayuangao tinayuangao merged commit 0d04229 into angular:tree Nov 14, 2017
tinayuangao added a commit that referenced this pull request Nov 15, 2017
* Add Cdk Tree component

* Put tree control in control folder. Removed NestedNode FlatNode types
and add getLevel getChildren isExpandable in TreeControl.

* Use static varaible to pass node data

* fix lint

* another round

* update documents according to comments
tinayuangao added a commit to tinayuangao/material2 that referenced this pull request Nov 16, 2017
* Add Cdk Tree component

* Put tree control in control folder. Removed NestedNode FlatNode types
and add getLevel getChildren isExpandable in TreeControl.

* Use static varaible to pass node data

* fix lint

* another round

* update documents according to comments
tinayuangao added a commit to tinayuangao/material2 that referenced this pull request Nov 16, 2017
* Add Cdk Tree component

* Put tree control in control folder. Removed NestedNode FlatNode types
and add getLevel getChildren isExpandable in TreeControl.

* Use static varaible to pass node data

* fix lint

* another round

* update documents according to comments
tinayuangao added a commit that referenced this pull request Nov 16, 2017
* Add Cdk Tree component

* Put tree control in control folder. Removed NestedNode FlatNode types
and add getLevel getChildren isExpandable in TreeControl.

* Use static varaible to pass node data

* fix lint

* another round

* update documents according to comments
tinayuangao added a commit to tinayuangao/material2 that referenced this pull request Nov 21, 2017
* Add Cdk Tree component

* Put tree control in control folder. Removed NestedNode FlatNode types
and add getLevel getChildren isExpandable in TreeControl.

* Use static varaible to pass node data

* fix lint

* another round

* update documents according to comments
tinayuangao added a commit that referenced this pull request Nov 21, 2017
* Add Cdk Tree component

* Put tree control in control folder. Removed NestedNode FlatNode types
and add getLevel getChildren isExpandable in TreeControl.

* Use static varaible to pass node data

* fix lint

* another round

* update documents according to comments
tinayuangao added a commit to tinayuangao/material2 that referenced this pull request Nov 27, 2017
* Add Cdk Tree component

* Put tree control in control folder. Removed NestedNode FlatNode types
and add getLevel getChildren isExpandable in TreeControl.

* Use static varaible to pass node data

* fix lint

* another round

* update documents according to comments
tinayuangao added a commit that referenced this pull request Nov 28, 2017
* Add Cdk Tree component

* Put tree control in control folder. Removed NestedNode FlatNode types
and add getLevel getChildren isExpandable in TreeControl.

* Use static varaible to pass node data

* fix lint

* another round

* update documents according to comments
tinayuangao added a commit that referenced this pull request Nov 29, 2017
* Add Cdk Tree component

* Put tree control in control folder. Removed NestedNode FlatNode types
and add getLevel getChildren isExpandable in TreeControl.

* Use static varaible to pass node data

* fix lint

* another round

* update documents according to comments
tinayuangao added a commit that referenced this pull request Nov 29, 2017
* Add Cdk Tree component

* Put tree control in control folder. Removed NestedNode FlatNode types
and add getLevel getChildren isExpandable in TreeControl.

* Use static varaible to pass node data

* fix lint

* another round

* update documents according to comments
tinayuangao added a commit that referenced this pull request Dec 9, 2017
* Add Cdk Tree component

* Put tree control in control folder. Removed NestedNode FlatNode types
and add getLevel getChildren isExpandable in TreeControl.

* Use static varaible to pass node data

* fix lint

* another round

* update documents according to comments
tinayuangao added a commit that referenced this pull request Dec 13, 2017
* Add Cdk Tree component

* Put tree control in control folder. Removed NestedNode FlatNode types
and add getLevel getChildren isExpandable in TreeControl.

* Use static varaible to pass node data

* fix lint

* another round

* update documents according to comments
tinayuangao added a commit that referenced this pull request Dec 14, 2017
* Add Cdk Tree component

* Put tree control in control folder. Removed NestedNode FlatNode types
and add getLevel getChildren isExpandable in TreeControl.

* Use static varaible to pass node data

* fix lint

* another round

* update documents according to comments
tinayuangao added a commit that referenced this pull request Dec 15, 2017
* Add Cdk Tree component

* Put tree control in control folder. Removed NestedNode FlatNode types
and add getLevel getChildren isExpandable in TreeControl.

* Use static varaible to pass node data

* fix lint

* another round

* update documents according to comments
tinayuangao added a commit to tinayuangao/material2 that referenced this pull request Dec 15, 2017
* Add Cdk Tree component

* Put tree control in control folder. Removed NestedNode FlatNode types
and add getLevel getChildren isExpandable in TreeControl.

* Use static varaible to pass node data

* fix lint

* another round

* update documents according to comments
tinayuangao added a commit that referenced this pull request Dec 19, 2017
* Add Cdk Tree component

* Put tree control in control folder. Removed NestedNode FlatNode types
and add getLevel getChildren isExpandable in TreeControl.

* Use static varaible to pass node data

* fix lint

* another round

* update documents according to comments
tinayuangao added a commit that referenced this pull request Jan 4, 2018
* Add Cdk Tree component

* Put tree control in control folder. Removed NestedNode FlatNode types
and add getLevel getChildren isExpandable in TreeControl.

* Use static varaible to pass node data

* fix lint

* another round

* update documents according to comments
tinayuangao added a commit that referenced this pull request Jan 10, 2018
* Add Cdk Tree component

* Put tree control in control folder. Removed NestedNode FlatNode types
and add getLevel getChildren isExpandable in TreeControl.

* Use static varaible to pass node data

* fix lint

* another round

* update documents according to comments
tinayuangao added a commit that referenced this pull request Jan 23, 2018
* Add Cdk Tree component

* Put tree control in control folder. Removed NestedNode FlatNode types
and add getLevel getChildren isExpandable in TreeControl.

* Use static varaible to pass node data

* fix lint

* another round

* update documents according to comments
expect(treeControl.expansionModel.selected.length)
.toBe(2, 'Expect two dataNodes in expansionModel');

treeControl.collapse(seconNode);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo seconNode -> secondNode

tinayuangao added a commit that referenced this pull request Feb 5, 2018
* Add Cdk Tree component

* Put tree control in control folder. Removed NestedNode FlatNode types
and add getLevel getChildren isExpandable in TreeControl.

* Use static varaible to pass node data

* fix lint

* another round

* update documents according to comments
tinayuangao added a commit that referenced this pull request Feb 9, 2018
* Add Cdk Tree component

* Put tree control in control folder. Removed NestedNode FlatNode types
and add getLevel getChildren isExpandable in TreeControl.

* Use static varaible to pass node data

* fix lint

* another round

* update documents according to comments
jelbourn pushed a commit that referenced this pull request Feb 12, 2018
* Add Cdk Tree component

* Put tree control in control folder. Removed NestedNode FlatNode types
and add getLevel getChildren isExpandable in TreeControl.

* Use static varaible to pass node data

* fix lint

* another round

* update documents according to comments
tinayuangao added a commit that referenced this pull request Feb 13, 2018
* Add Cdk Tree component

* Put tree control in control folder. Removed NestedNode FlatNode types
and add getLevel getChildren isExpandable in TreeControl.

* Use static varaible to pass node data

* fix lint

* another round

* update documents according to comments
@angular-automatic-lock-bot
Copy link

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Sep 8, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
action: merge The PR is ready for merge by the caretaker cla: yes PR author has agreed to Google's Contributor License Agreement
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants