Aleksandr Popov
Aleksandr Popov

Reputation: 520

Angular - Get parent component receive data after init

I have Angular front end which fetches data from Lumen backend:

ngAfterViewInit() {

    merge()
      .pipe(
        startWith({}),
        switchMap(() => {
          this.isLoadingResults = true;
          return this.exampleDatabase!.getRepoIssues(this.itemId);
        }),
        map(data => {
          this.isLoadingResults = false;
          this.isRateLimitReached = false;

          return data;
        }),
        catchError(() => {
          this.isLoadingResults = false;
          this.isRateLimitReached = true;
          return observableOf([]);
        })
      ).subscribe(
      data => this.applyDataChanges(data)
    );
  }

  private applyDataChanges(data: any) {
    let tree = [];

    for(let b of data.buildings) {
      let children = [];
      for(let c of b.buildings){
        children.push(new ChecklistNodeModel(c.name, false))
      }
      tree.push(new ChecklistNodeModel(b.group.name, false, children));
    }

    this.TREE_DATA = tree;

    this.itemId > 0 ?
      this.form = data as ControllingCompanyNewsModel :
      this.form = new ControllingCompanyNewsModel(0,null,'','','', data.buildings);
  }

Parent component has following property which then passes through @Input binding to child component:

  <app-checklist-tree [treeData]="TREE_DATA"></app-checklist-tree>

and

  @Input() treeData = [];

The question is for sone reason the child component has empty treeData property. While parent component has property updated correctly.

Could anyone advice where I made a mistake? Thank you!

Adding child component code

export class ChecklistTreeComponent implements AfterViewInit, OnChanges {

  @Input() treeData = [];
  @Output() treeDataChange = new EventEmitter<ChecklistNodeModel[]>();
  levels = new Map<ChecklistNodeModel, number>();
  treeControl: FlatTreeControl<ChecklistNodeModel>;

  treeFlattener: MatTreeFlattener<ChecklistNodeModel, ChecklistNodeModel>;

  dataSource: MatTreeFlatDataSource<ChecklistNodeModel, ChecklistNodeModel>;

  constructor(private changeDetectorRef: ChangeDetectorRef) {
    this.treeFlattener = new MatTreeFlattener(this.transformer, this.getLevel,
      this.isExpandable, this.getChildren);
    this.treeControl = new FlatTreeControl<ChecklistNodeModel>(
      this.getLevel, this.isExpandable);
    this.dataSource = new MatTreeFlatDataSource(this.treeControl, this.treeFlattener);
    // this.dataSource = new MatTreeFlatDataSource(this.treeControl, this.treeFlattener);
    this.dataSource.data = this.treeData;
  }



  getLevel = (node: ChecklistNodeModel): number => {
    return this.levels.get(node) || 0;
  };

  isExpandable = (node: ChecklistNodeModel): boolean => {
    return node.children.value.length > 0;
  };

  getChildren = (node: ChecklistNodeModel) => {
    return node.children;
  };

  transformer = (node: ChecklistNodeModel, level: number) => {
    this.levels.set(node, level);
    return node;
  }

  hasChildren = (index: number, node: ChecklistNodeModel) => {
    return this.isExpandable(node);
  }

  /** The selection for checklist */
  checklistSelection = new SelectionModel<ChecklistNodeModel>(true /* multiple */);

  /** Whether all the descendants of the node are selected */
  descendantsAllSelected(node: ChecklistNodeModel): boolean {
    const descendants = this.treeControl.getDescendants(node);
    if (!descendants.length) {
      return this.checklistSelection.isSelected(node);
    }
    const selected = this.checklistSelection.isSelected(node);
    const allSelected = descendants.every(child => this.checklistSelection.isSelected(child));
    if (!selected && allSelected) {
      this.checklistSelection.select(node);
      this.changeDetectorRef.markForCheck();
    }
    return allSelected;
  }

  /** Whether part of the descendants are selected */
  descendantsPartiallySelected(node: ChecklistNodeModel): boolean {
    const descendants = this.treeControl.getDescendants(node);
    if (!descendants.length) {
      return false;
    }
    const result = descendants.some(child => this.checklistSelection.isSelected(child));
    return result && !this.descendantsAllSelected(node);
  }

  /** Toggle the selection. Select/deselect all the descendants node */
  nodeSelectionToggle(node: ChecklistNodeModel): void {
    node.checked = !node.checked;
    this.checklistSelection.toggle(node);
    const descendants = this.treeControl.getDescendants(node);
    if(this.checklistSelection.isSelected(node)) {
      this.checklistSelection.select(...descendants, node);
      for(let descendant of descendants) {
        this.nodeSelectionToggle(descendant);
      }
    } else {
      this.checklistSelection.deselect(...descendants, node);
      for(let descendant of descendants) {
        this.nodeSelectionToggle(descendant);
      }
    }
    this.changeDetectorRef.markForCheck();
  }

  ngAfterViewInit(): void {
    this.dataSource.data = this.treeData;
  }

  ngOnChanges(changes: SimpleChanges): void {
    this.dataSource.data = changes.treeData.currentValue;
  }


}

Upvotes: 0

Views: 493

Answers (1)

Ranika Nisal
Ranika Nisal

Reputation: 980

Implement this in the parent component

//import CheckListTreeComponent
//Import viewChild from angular core
export class ParentClass {
      @ViewChild(ChecklistTreeComponent)
      private tree : ChecklistTreeComponent;

      constructor(){}
      //
}

At the point you are sure that the parent component has received it's value

this.tree.update(this.TREE_DATA)

In the child component

update(value){
     this.treeData = value;
}

Upvotes: 1

Related Questions