2

I'm working with localStorage and I want to change a counter when closing the page.

I found that onbeforeunload is the event which can be useful, so I decided to call my function in it. (onunload doesn't work for me in firefox/chrome)

But when I try to call a function , it doesn't do anything.

Is there any way to call a function when closing/refreshing a tab ?

class MyLib{
   constructor(){
        window.onbeforeunload = function() {
            this._onClosePage();
        };
   }

    _onClosePage() {
        let openWindowsCount = this._getItem('countOpenWindow');
        openWindowsCount--;
        if (openWindowsCount === 0) {
            this._clearUp();
        }
    }

    _clearUp() { 
        this._removeItem('countPagesVisited');
    }
}

UPDATE

As suggested by Oday , I fixed the binding. But now , it works randomly.

In chrome, it doesn't catch the refresh event, but sometimes it catches the exit.

In firefox, it catches the exit, and randomly catches the refresh.

class MyLib{
   constructor(){
     document.getElementsByTagName('body')[0].onbeforeunload = this._onClosePage.bind(this);
   }

    _onClosePage() {
        let openWindowsCount = this._getItem('countOpenWindow');
        openWindowsCount--;
        if (openWindowsCount === 0) {
            this._clearUp();
        }
    }
    _onClosePage() { // call it once the page is closed or refreshed
        let openWindowsCount = localStorage.getItem('countOpenWindow');
        openWindowsCount--;
        localStorage.setItem('countOpenWindow' , openWindowsCount);
        if (openWindowsCount === 0) {
            this._clearUp();
        }
    }
    _clearUp() { 
        localStorage.removeItem('countOpenWindow');
    }
}
Arian
  • 7,397
  • 21
  • 89
  • 177
  • Please, attach the event handler assigned to the onbeforeunload event – Oday Fraiwan Nov 03 '15 at 07:36
  • @Oday : edited the question and added the code – Arian Nov 03 '15 at 07:40
  • Is there an error displayed in the browser console ? – Oday Fraiwan Nov 03 '15 at 07:45
  • @Oday: No , it doesn't do anything. – Arian Nov 03 '15 at 07:50
  • This is risky as there are many things than can make page go away. May I ask what you store when page unloads and what that "what" do? – Asons Nov 03 '15 at 17:44
  • You could go the opposite way, everytime a user comes back (and have a value in the storage), then you decrease the counter. This way you always are in control. – Asons Nov 03 '15 at 18:02
  • @LGSon: (I corrected my comment) I want to keep the number of tabs/pages of my website that a user has open, in order to make an ajax call when this number exceeds a certain number. Or when the user spends more than some amount of time on my website, I want to make an ajax call. The problem is with localStorage, it seems that I need to clean it up when the user has no more open pages of my website. because if I don't next time that the user comes back to my website, it still has those values in the storage. – Arian Nov 03 '15 at 18:04
  • So you don't need to keep this counter between 2 sessions? – Asons Nov 03 '15 at 18:06
  • @LGSon : I need to keep it between two tabs , but when user leaves the website (closed all tabs) I need to reset all the values I stored in the localStorage, so next time I count from 0. – Arian Nov 03 '15 at 18:07
  • Ok, do you use ASP or PHP or some other server side language? – Asons Nov 03 '15 at 18:07
  • @LGSon : What you suggested (doing it onload) doesn't work in my case. – Arian Nov 03 '15 at 18:11
  • @LGSon : Ignore my previous comment, I make a an ajax call , whenever the number of open tabs or the amount of time spent exceeds a value. – Arian Nov 03 '15 at 18:12
  • @LGSon : The problem is when a user closes all the tabs, we still have those numbers in stored in the localStorage, so if the user comes back in 10 minutes . We still have those values in the storage which is not valid anymore. – Arian Nov 03 '15 at 18:14
  • Check this answer for the best approach if you need to do this with a high precision: http://stackoverflow.com/a/12069259/2827823 ... the other solution is server side session variables ... further reading: http://phillbarber.blogspot.no/2014/02/client-side-vs-server-side-session.html – Asons Nov 03 '15 at 18:24

2 Answers2

3

In order to clean the localStorage on beforeunload, instead of using window.onbeforeunload directly, you should use the window.addEventListener() method to start listening to beforeunload event. This also allows you to remove the event listener when you find fit.

See this explanation on Mozilla Developers Documentation:

Binding to this event can be used to prevent the browser from fully caching the page in cases where content is rendered by javascript. In certain circumstances when returning to a page that has executed javascript in order to populate content, you may find the javascript not running upon the return visit when navigating back. If window.onbeforeunload has been bound (and thus triggered when leaving that page) javascript in the page will be triggered on the subsequent return visit and therefore update the content.

Full text here: https://developer.mozilla.org/en-US/docs/Web/API/WindowEventHandlers/onbeforeunload

This is probably the reason for the randomness you mentioned.

As an example, see above React component that adds the event listener when it finishes mounting, and than, when it is unmounted it removes the event listener. It is a very elementary example, but I tested it on Firefox 60, Chrome 69 canary, Safari 11.1 and it worked properly.

import React, { Component } from 'react'

class App extends Component {
  constructor(props) {
    super(props)
    this.handleLoad = this.handleLoad.bind(this)
    this.handleBeforeunload = this.handleBeforeunload.bind(this)
  }

  componentDidMount() {
    this.handleLoad()
    window.addEventListener('beforeunload', this.handleBeforeunload)
  }

  componentWillUnmount() {
    window.removeEventListener('beforeunload', this.handleBeforeunload)
  }

  render() {
    return (
      <div className="App">
        <p>
          Hello World!
        </p>
      </div>
    )
  }

  handleLoad() {
    let countOpenWindow = parseInt(localStorage.getItem('countOpenWindow'), 10)
    if (!countOpenWindow) {
      countOpenWindow = 0
    }

    localStorage.setItem('countOpenWindow', ++countOpenWindow)
  }

  handleBeforeunload() {
    let countOpenWindow = parseInt(localStorage.getItem('countOpenWindow'), 10)
    if (countOpenWindow > 1) {
      localStorage.setItem('countOpenWindow', --countOpenWindow)
    } else {
      localStorage.removeItem('countOpenWindow')
    }
  }
}

export default App
1

You need to capture the context of your class inside the onbeforeunload event handler. Currently, the 'this' refers to the window which fires the event.

constructor(){
    let that = this;
    window.onbeforeunload = function() {
        that._onClosePage();
    };
}
Oday Fraiwan
  • 1,147
  • 1
  • 9
  • 21
  • In chrome , when I refresh the page it doesn't call the function. I firefox it does. (in chrome it's pretty much random , even when closing). Do you have any idea why this happens ? – Arian Nov 03 '15 at 09:58
  • Could you post the region of code where you create an instant of the Class – Oday Fraiwan Nov 03 '15 at 11:17