title: Angular 6 Material Tree collapse functionality is not working properly
body: <p>Currently I'm trying to develop a tree structure for dynamic data using Angular material tree component and I followed the code example mention below:</p>
  
  <p><a href="https://stackblitz.com/edit/material-tree-dynamic" rel="nofollow noreferrer">https://stackblitz.com/edit/material-tree-dynamic</a></p>
  
  <p>Since the tree which I have developed is not working properly, I copied above code as it is and try to run in my machine. but the collapse functionality is not working. Here is my typescript file (html is exactly the same):</p>
  
  <pre><code>import {Component, Injectable} from '@angular/core';
  import {FlatTreeControl} from '@angular/cdk/tree';
  import {CollectionViewer, SelectionChange} from '@angular/cdk/collections';
  import {BehaviorSubject} from 'rxjs/BehaviorSubject';
  import {Observable} from 'rxjs/Observable';
  import {merge} from 'rxjs/observable/merge';
  import {map} from 'rxjs/operators/map';
  
  
  /** Flat node with expandable and level information */
  export class DynamicFlatNode {
    constructor(public item: string, public level: number = 1, public expandable: boolean = false, public isLoading: boolean = false) {}
  }
  
  /**
   * Database for dynamic data. When expanding a node in the tree, the data source will need to fetch
   * the descendants data from the database.
   */
  export class DynamicDatabase {
    dataMap = new Map([
      ['Simulation', ['Factorio', 'Oxygen not included']],
      ['Indie', [`Don't Starve`, 'Terraria', 'Starbound', 'Dungeon of the Endless']],
      ['Action', ['Overcooked']],
      ['Strategy', ['Rise to ruins']],
      ['RPG', ['Magicka']],
      ['Magicka', ['Magicka 1', 'Magicka 2']],
      [`Don't Starve`, ['Region of Giants', 'Together', 'Shipwrecked']]
    ]);
  
    rootLevelNodes = ['Simulation', 'Indie', 'Action', 'Strategy', 'RPG'];
  
    /** Initial data from database */
    initialData(): DynamicFlatNode[] {
      return this.rootLevelNodes.map(name =&gt; new DynamicFlatNode(name, 0, true));
    }
  
  
    getChildren(node: string): string[] | undefined {
      return this.dataMap.get(node);
    }
  
    isExpandable(node: string): boolean {
      return this.dataMap.has(node);
    }
  }
  /**
   * File database, it can build a tree structured Json object from string.
   * Each node in Json object represents a file or a directory. For a file, it has filename and type.
   * For a directory, it has filename and children (a list of files or directories).
   * The input will be a json object string, and the output is a list of `FileNode` with nested
   * structure.
   */
  @Injectable()
  export class DynamicDataSource {
  
    dataChange: BehaviorSubject&lt;DynamicFlatNode[]&gt; = new BehaviorSubject&lt;DynamicFlatNode[]&gt;([]);
  
    get data(): DynamicFlatNode[] { return this.dataChange.value; }
    set data(value: DynamicFlatNode[]) {
      this.treeControl.dataNodes = value;
      this.dataChange.next(value);
    }
  
    constructor(private treeControl: FlatTreeControl&lt;DynamicFlatNode&gt;,
                private database: DynamicDatabase) {}
  
    connect(collectionViewer: CollectionViewer): Observable&lt;DynamicFlatNode[]&gt; {
      this.treeControl.expansionModel.onChange!.subscribe(change =&gt; {
        if ((change as SelectionChange&lt;DynamicFlatNode&gt;).added ||
          (change as SelectionChange&lt;DynamicFlatNode&gt;).removed) {
          this.handleTreeControl(change as SelectionChange&lt;DynamicFlatNode&gt;);
        }
      });
  
      return merge(collectionViewer.viewChange, this.dataChange).pipe(map(() =&gt; this.data));
    }
  
    /** Handle expand/collapse behaviors */
    handleTreeControl(change: SelectionChange&lt;DynamicFlatNode&gt;) {
      if (change.added) {
        change.added.forEach((node) =&gt; this.toggleNode(node, true));
      }
      if (change.removed) {
        change.removed.reverse().forEach((node) =&gt; this.toggleNode(node, false));
      }
    }
  
    /**
     * Toggle the node, remove from display list
     */
    toggleNode(node: DynamicFlatNode, expand: boolean) {
      const children = this.database.getChildren(node.item);
      const index = this.data.indexOf(node);
      if (!children || index &lt; 0) { // If no children, or cannot find the node, no op
        return;
      }
  
  
      if (expand) {
        node.isLoading = true;
  
        setTimeout(() =&gt; {
          const nodes = children.map(name =&gt;
            new DynamicFlatNode(name, node.level + 1, this.database.isExpandable(name)));
          this.data.splice(index + 1, 0, ...nodes);
          // notify the change
          this.dataChange.next(this.data);
          node.isLoading = false;
        }, 1000);
      } else {
        this.data.splice(index + 1, children.length);
        this.dataChange.next(this.data);
      }
    }
  }
  
  @Component({
    selector: 'app-audience-tree',
    templateUrl: './audience-tree.component.html',
    styleUrls: ['./audience-tree.component.css'],
    providers: [DynamicDatabase]
  })
  export class AudienceTreeComponent{
  
    constructor(database: DynamicDatabase) {
      this.treeControl = new FlatTreeControl&lt;DynamicFlatNode&gt;(this.getLevel, this.isExpandable);
      this.dataSource = new DynamicDataSource(this.treeControl, database);
  
      this.dataSource.data = database.initialData();
    }
  
    treeControl: FlatTreeControl&lt;DynamicFlatNode&gt;;
  
    dataSource: DynamicDataSource;
  
    getLevel = (node: DynamicFlatNode) =&gt; { return node.level; };
  
    isExpandable = (node: DynamicFlatNode) =&gt; { return node.expandable; };
  
    hasChild = (_: number, _nodeData: DynamicFlatNode) =&gt; { return _nodeData.expandable; };
  
  
  }
  </code></pre>
  
  <p>When I collapse a root node which has more than 1 children level
  <a href="https://i.stack.imgur.com/rtQK6.png" rel="nofollow noreferrer">this result will be given</a></p>
  
  <p>So guys, can anybody tell me what is the reason for that? And how can I fix that? It would be a great help.</p>