Reputation: 158
I have a click event (updateExpanded) on my parent, when clicked I fire and event off that goes to the child. the child then subscribes to this event. The problem is that the event gets called 4 times. I have tried everything I could find but just cant seem to see why it gets fired so often when it should only get fired once.
I need to load data in my child component when my parent component gets expanded.
Parent TS
@Output()
isExpandedEvent = new EventEmitter<string>();
updateExpanded(id: string) {
this.isExpandedEvent.emit(id);
console.log(id + " parent opened");
}
ngOnDestroy() {
if (this.isExpandedEvent) {
this.isExpandedEvent.unsubscribe();
}
}
Parent HTML
<ngx-planned-maintenance-detail [model]="plannedMaintenanceRecurring" [index]="i" [expandedEventEmitter]="isExpandedEvent">
</ngx-planned-maintenance-detail>
.........
Child TS
@Input()
expandedEventEmitter = new EventEmitter<string>();
ngOnInit() {
this.expandedEventEmitter.subscribe(data => {
if (data) {
console.log("detail complete");
}
});
}
ngOnDestroy() {
this.expandedEventEmitter.unsubscribe();
}
Parent is called once, detail called 4 times as seen below
Upvotes: 0
Views: 2998
Reputation: 1880
use a ViewChild
to send click events to a child.
use EventEmitter
to send click events from the child up to the parent.
Upvotes: 0
Reputation: 31135
That's because you are binding an observable (the EventEmitter
) to a property. There are 2 issues here.
EventEmitter
is NOT the correct way to communicate information from parent to child. It's used for the other way around.If you look at the EventEmitter
source, it's a simple interface extension of RxJS Subject
. So what you could do in this instance is to create a singleton service that will hold the shared information between the components directly using a RxJS Subject
.
shared.service.ts
import { Subject } from 'rxjs';
@Injectable({providedIn: 'root'})
export class SharedService {
isExpanded = new Subject<any>();
constructor() { }
pushIsExpanded(value: any) {
this.isExpanded.next(value);
}
getIsExpanded() {
return this.isExpanded.asObservable();
}
}
Now you could inject this singleton in both the components and use the shared data.
parent.component.ts
export class ParentComponent {
constructor(private sharedService: SharedService) { }
updateExpanded(id: string) {
this.sharedService.pushIsExpanded(id);
}
}
child.component.ts
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
export class ChildComponent {
const completed$ = new Subject<any>();
constructor(private sharedService: SharedService) { }
ngOnInit() {
this.sharedService.getIsExpanded().pipe(
takeUntil(this.completed$)
).subscribe(
data => {
if (data) {
console.log("detail complete");
}
}
);
}
ngOnDestroy() {
this.completed$.next();
this.completed$.complete();
}
}
Upvotes: 2