21

So I'm trying to improve my angular skills and I'm currently working on a forum.

I had the idea of showing the users how many users are currently online. When they enter the forum part of the website, I update my database to add one member to the count and when they leave, it deducts one from that same database.

I thought I had it all figured when I added the plus-one logic to the ngOnInit() and the deduct-one to the ngOnDestroy, but then I noticed that when I refreshed the page with f5 that the ngOndestroy() hadn't fired. The result is that it keeps adding members to the member count even though it's always the same person looking at the page.

How can I make sure the count deducts one when the person navigates to another part of my SPA AND when he refreshes the page?

My code: in ngOnDestroy I do the server request to deduct one in the database and then unsubscribe from all the observables in the component

export class ForumCountComponent implements OnInit, OnDestroy{

    data;
    ngUnsubscribe = new Subject();

    constructor(private authService: AuthenticationService, private forumService: ForumService){

    }

    ngOnInit(){
        let loggedIn = this.authService.isLoggedIn();

        this.forumService.forumCountPlus(loggedIn)
            .takeUntil(this.ngUnsubscribe)
            .subscribe((data) => {
                this.data = data;
                console.log(data);
            })
    }

    ngOnDestroy(){
        let loggedIn = this.authService.isLoggedIn();

        this.forumService.forumCountMin(loggedIn)
            .takeUntil(this.ngUnsubscribe)
            .subscribe((data) => {
                this.data = data;
                this.ngUnsubscribe.next();
                this.ngUnsubscribe.complete();
            })
    }
tilly
  • 2,229
  • 9
  • 34
  • 64

1 Answers1

41

ngOnDestroy only fires when the component is destroyed inside the angular workflow. However, refreshing the page is outside of the workflow and so this method does not fire. To handle an action when the user leaves/refreshes the page you need to use onbeforeunload.

ngOnInit(){
    let loggedIn = this.authService.isLoggedIn();

    this.forumService.forumCountPlus(loggedIn)
        .takeUntil(this.ngUnsubscribe)
        .subscribe((data) => {
            this.data = data;
            console.log(data);
        })

    window.onbeforeunload = () => this.ngOnDestroy();
}

ngOnDestroy(){
    let loggedIn = this.authService.isLoggedIn();

    this.forumService.forumCountMin(loggedIn)
        .takeUntil(this.ngUnsubscribe)
        .subscribe((data) => {
            this.data = data;
            this.ngUnsubscribe.next();
            this.ngUnsubscribe.complete();
        })
}
Teddy Sterne
  • 13,774
  • 2
  • 46
  • 51
  • 1
    works only for 1 component. If you need 2 or more components ngOnDestroy get triggered on browser refresh, you need a mechanism like queuing. – Develobba Mar 16 '20 at 13:46
  • This is a very elegant method - for a single component. Thanks for the suggestion! – Bas Kuis Jan 18 '22 at 03:36
  • Be aware beforeunload is not reliable as the Usage notes mention. Especially on Mobile! So i do not put logic there that is essential for the app to work. – JIT Solution Aug 01 '22 at 08:52