1

I'm building a dashboard to manage users inside a company. That company has different numbers of departments and a bunch of filials inside those departments, so I have a custom recursive Tree View to display the association between those.

Now, when I click on a certain branch of the tree, I need to send a single number that identifies that department / filial (cd) from the tree to the parent component, where is displayed the relative workers and data about them. In the parent component, that number is used to fetch from the database all the data relative to that department / filial.

For it, I've read in forums that I could use the @Input / @Output decorators and EventEmitter. It's working, but only once. the method that receives the cd ( called receiveNode() ) doesn't update when I click on another branch and only works in the first branch. Which is not the desired behaviour.

For testing, in the same method that emits the CD variable, I log to the console the CD of the branch. I can see that I can log the CD variable every time I click the branch, but only sends once through the Event Emitter

tree.component.ts (child)

import { Component, OnInit, Output, EventEmitter } from '@angular/core';
import { Input } from '@angular/core';
import { TreeNode } from '../../interfaces/tree-node';

@Component({
  selector: 'app-tree',
  templateUrl: './tree.component.html',
  styleUrls: ['./tree.component.css']
})
export class TreeComponent implements OnInit {

  @Input() treeData: TreeNode[];

  // Enviar CD do organigrama para o BuildOrganigComponent
  @Output() eventEmitter: EventEmitter<number> = new EventEmitter();
  nome: string;

  constructor() {  }

  ngOnInit() { }

  toggleChild(node) { node.showChildren = !node.showChildren; }

  sendNode(cd) {
    console.log(cd);
    this.eventEmitter.emit(cd);
  }
}

tree.component.html

<ul *ngIf="treeData">
  <li *ngFor="let node of treeData">
    <span *ngIf="node.children != 0">
      <i (click)="toggleChild(node)" id="seta-direita" class="fas fa-angle-right fa-fw"></i>
    </span>
    <span id="row" (click)="sendNode(node.cd)">{{ node.nome }}</span>
    <app-tree *ngIf="!node.showChildren" [treeData]="node.children"></app-tree>
  </li>  
</ul>

funcion.component.ts

  receiveNode(e) {
    console.log(e);
  }

funcion.component.html

 <div class="overflow" style="margin-left: -5% !important;">
        <app-tree [treeData]='nodes' (eventEmitter)='receiveNode($event)'></app-tree>
    </div>

funcion.html and funcion.ts are quite large, so only placed the important stuff. If need to see the whole code, just tell me.

Some images Parent component with the tree inside it

Details in the console

In the second image, we can see that logs from the tree components and the funcion component, but after, wherever I click, it never calls the method in the funcion components.

What may be wrong? Any help is appreciated

LuisMorais
  • 162
  • 4
  • 16
  • Are you trying to use the component in its own template? i don't think that's a good idea or even valid? – alokstar Oct 22 '18 at 17:34
  • It's a recursive way to do it... At least, as I understood. I found on the Internet and worked so far. But feels 'wrong', if I think about it :/ – LuisMorais Oct 22 '18 at 17:40
  • 2
    It might put your application calls on loop! I would not suggest this. Why don't you create separate parent and child components and try? By doing this, it will be easy for you to understand the data-flow. You can even put breakpoints on functions and see what function or line of code getting executed and when, which will clear all the doubts you have! – alokstar Oct 22 '18 at 17:44
  • Humm, ok, I'll check it out. Maybe I should think and redesign the whole tree componente. Thanks – LuisMorais Oct 23 '18 at 07:50

1 Answers1

1

I managed to make it work by passing the data through a shared service rather than @Input and @Output decorators. Now it's simpler, cleaner and easier to understand!

data.service.ts

import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';

@Injectable()
export class DataService {

  private cdSource = new BehaviorSubject<number>(1);
  currentCD = this.cdSource.asObservable();

  constructor() { }

  changeCD(m: number) {
    this.cdSource.next(m);
  }

}

child.component.ts

// Called everythime treeview is clicked
sendNode(cd: number) {
  this.dataService.changeCD(cd);
}

parent.component.ts

 // Update methods when dataService changes values
    this.dataService.currentCD.subscribe(message => {
      this.preencheGrafico(message);
      this.preencheDadosIniciais(message);
      this.preencheTabela(message);
  });
}

Worked like a charm and no flaws whatsoever!

Based on this tutorial

fiza khan
  • 1,280
  • 13
  • 24
LuisMorais
  • 162
  • 4
  • 16