Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular EventEmitter called multiple times

This is really strange and hard to explain. I have use EventEmitter in a few of my services and I have been using it to change data on my views. I have had an issue with change routes (via links or via history back) where it seems to be firing multiple times and because of this it is messing up my logic.

So I created a test on stackblitz to see if I could recreate it. I made a simple service:

import { Injectable, Output, EventEmitter } from '@angular/core';

@Injectable()
export class ListService {
@Output() listChanged: EventEmitter<any[]> = new EventEmitter<any[]>()

  constructor() { }

  list() {
    this.listChanged.emit([]);
  }
}

and then in one of my routes, I just do this:

import { Component, OnInit } from '@angular/core';

import { ListService } from '../list.service';

@Component({
  selector: 'app-products',
  templateUrl: './products.component.html',
  styleUrls: ['./products.component.css']
})
export class ProductsComponent implements OnInit {
  count: any[] = []

  constructor(
    private listService: ListService
  ) { }

  ngOnInit() {
    this.listService.listChanged.subscribe(() => {
      this.count.push('invoked');
      console.log('invoked');
      console.log('------');
    });
    this.listService.list();
  }
}

And I then created a simple template like this:

<p>
  Invoke should only be called once
</p>

<ul>
  <li *ngFor="let item of count">{{ item }}</li>
</ul>

When you navigate between routes, it looks like it is working as expected (the ngFor should only ever have one item), but if you open the console and have a look, you will see that each time you go from one view and back, it fires an extra time.

  • So, the first visit you will see the console output once.
  • Clear the console and move between views and you will see the console output twice.
  • Clear the console and move between views and you will see the console output three times.....

This will keep happening every time you swap views. Here is the stackblitz link so you can see it yourself.

https://stackblitz.com/edit/angular-sthags

Can anyone tell me why this is happening and how to stop it?

like image 787
r3plica Avatar asked Nov 27 '18 18:11

r3plica


1 Answers

This is because you are not killing the subscription when your component destroys (causing the memory leak by creating new subscriptions everytime your Products component initializes)

Assign the subscription to a class variable, use the ngOnDestroy() hook to kill the subscription.

subsVar: Subscription;

ngOnInit() {
    this.subsVar = this.listService.listChanged.subscribe(() => {
      this.count.push('invoked');
      console.log('invoked');
      console.log('------');
    });
}

ngOnDestroy() {
   if (this.subsVar) {
      this.subsVar.unsubscribe()
    }
}

https://stackblitz.com/edit/angular-9rvxgv?file=src/app/products/products.component.ts

like image 116
Ashish Ranjan Avatar answered Oct 21 '22 08:10

Ashish Ranjan