Reputation:
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.
Upvotes: 1
Views: 3770
Reputation:
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
Upvotes: 2