Search code examples
javascriptangularjspopupwindowaddeventlistener

Avoid from adding event listeners several times


I have an Office add-in which can open a popup browser window by

popup = window.open("https://localhost:3000/#/new", "popup", "status=1, location=1, width=1000, height=1200")

This page is coded by angular. To enable the communication between the add-in and the popup, I have added a listener in the controller. As a result, they can send messages to each other by postMessage.

app.controller("Ctrl", ["$scope", "$window", function($scope, $window) {
    ... ...
    $window.addEventListener("message", receiveMessage, false);
}

The communication works, except when the add-in changes the url of the popup to newUrl (where newUrl is another page instance which uses the same controller), by

popup.location.href = newUrl

Visually, the popup has changed, however the previous listener is not removed. As a result, one message sent by the add-in is received and treated twice (ie, by the new page and the previous page).

Does anyone know how to properly clean the listener when the add-in changes the popup page?


Solution

  • The comment of Cenk is correct: the event-remove and event-add logic must be in exactly the same function scope.

    So, on the side of the add-in, when the popup changes to another Url, I need to send manually a close message by postMessage to the page:

    popup.postMessage({ "req": "close" }, popup.location.href);
    popup.location.href = url
    

    On the side of the popup page, I could remove the listener in the receiveMessage, because it is still in the same page/function scope:

    app.controller("Ctrl", ["$scope", "$window", function($scope, $window) {
        ... ...
        var receiveMessage = function (event) {
            ... ...
            switch (event.data) {
                ... ...
                case "close": 
                    $window.removeEventListener("message", receiveMessage, false)
            }
        }
    }])