angular / components

Component infrastructure and Material Design components for Angular
https://material.angular.io
MIT License
24.35k stars 6.74k forks source link

help(Tree): TreeControl selection model doesn't work for immutable data #21422

Open alvipeo opened 3 years ago

alvipeo commented 3 years ago

Please see this - https://stackoverflow.com/q/65412659/2896495.

I needed a dynamically loading nodes in the angular material tree, so I created my own GeoDataSource which internally uses @ngrx/component-store to handle all the interaction between data source, TreeControl and the tree itself.

Now, the problem is the tree doesn't keep its expansion state because the abstract class BaseTreeControl<T, K = T> uses SelectionModel<T> class and this in turn uses Set<T> to keep track of items that are selected. So if node is expanded it just does this:

this._selection.add(value); // Set<T>.add(value)

When using immutable data (from the component store) those items are always new.

I tried to use trackBy optional function:

    this.treeControl = new FlatTreeControl<SomeEntityFlatNode, string>(
      (node) => node.nodeLevel,
      (node) => node.expandable, {
        trackBy: (node) => node.groupPath // *** groupPath is string (it's an ID) ***
      }
    );

and for this I had to change FlatTreeControl<SomeEntityFlatNode> to FlatTreeControl<SomeEntityFlatNode, string>, otherwise it doesn't compile. But then I got the following error in the template:

Type 'FlatTreeControl<SomeEntityFlatNode, string>' is not assignable to type 'TreeControl<SomeEntityFlatNode, SomeEntityFlatNode>'

Here's the template:

<mat-tree *ngIf="hasData$ | async" [dataSource]="geoDataSource" [treeControl]="treeControl">
</mat-tree>

Now what? How do I make all this work with immutable data from the store?

alvipeo commented 3 years ago

Also, see related bug - https://github.com/angular/components/issues/21364

alvipeo commented 3 years ago

This same bug does not allow to implement last leaf delete behavior - when the last leaf is deleted its parent doesn't change its state (its expandable state stays the same but should change to "non-expandable" as there are no children anymore).

Cubelaster commented 1 year ago

It seems I am experiencing the same issue. Or a lot of issues related to this. The tree does not react to change in data. Specifically, any change in the child is not reflected on the parent. This means adding children when there are none, or deleting every child won't trigger change in the parent. However, this is the way Angular works by default, so I'm guessing, from everything I've read, that we just need to redraw entire component from scratch every time in order to make it work correctly? Which would then kill some features, I'm guessing. Specifically, we would manually need to track opened and selected items...

Cubelaster commented 1 year ago

This issue is an detailed overview of the problem