Correctly removing event listeners in SAPUI5

In my web projects I was often asked what to do if you don't want to listen for a certain event anymore? The answer is removing the event listeners. But for some reason developers often do not know how to do that correctly. In this tutorial I would like to demonstrate a way in SAPUI5 you can correctly remove event listeners in case you don't need them anymore. For demonstration purposes we will simply create a Button control and register an event listener for its press event. The press event handler callback function alerts a simple notification before it removes the event listener from the button that was clicked. That means after the button has been clicked the first time by the user any subsequent click on the button will not trigger our event listener callback because we have removed the event listener when the button was clicked the first time. Let's see how it works:


correctlyRemovingEventListeners.html (live demo)
<!DOCTYPE html>
<html lang="en">
    <head>
        <title>Correctly Removing Event Listeners with SAPUI5</title>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        
        <script id="sap-ui-bootstrap"
            src="https://openui5.hana.ondemand.com/1.36.12/resources/sap-ui-core.js"
            data-sap-ui-theme="sap_bluecrystal"
            data-sap-ui-libs="sap.ui.commons">
        </script>
        
        <style>
            /* here you could overwrite some sapui5 styles you don't like */
        </style>
        
        <script>
            var oBtn, fnPressHandler;
            
            fnPressHandler = function (oEvent) {
                var src;
                
                alert("fnPressHandler(oEvent) has been called");
                
                //we will not use this although this would work in our use case
                //this.detachPress(fnPressHandler);
                
                src = oEvent.getSource();
                if (src instanceof sap.ui.commons.Button) {
                    alert("Now remove the handler function for press event");
                    src.detachPress(fnPressHandler);
                    //from now on fnPressHandler() will not be called when ever
                    //the button is pressed
                } 
            };
            
            oBtn = new sap.ui.commons.Button({
                text : "detachPress"
            });
            oBtn.attachPress(fnPressHandler);
            oBtn.placeAt("content");
            
        </script>
        
    </head>
    
    <body class="sapUiBody" role="application">
        <div id="content"></div>
    </body>
    
</html>

As you can see above in line 22 we create a function and assign it to the variable fnPressHandler. Assigning it to a variable is important because only that way you know later which of the event listeners you want to remove. Keep in mind that you could possible have attached multiple press event listeners to the button and you need a way to remove one of them. Inside of fnPressHandler the first thing we do is displaying a simple dialog to demonstrate that the event listener is really called initially. Then we call oEvent.getSource(); to find out where the event actually comes from. oEvent is a parameter which is automatically passed by the SAPUI5 framework to our event listener. Next we want to call detachPress(fnPressHandler) to remove our event listener. As you can see it is important to pass the reference to our event listener function which we attached previously. That way the SAPUI5 framework knows which of the press event listeners is requested to be removed. Before calling detachPress(fnPressHandler) we want to make sure that the source of the event is a Button control. Only then we can assure that a detachPress(...) function is definitely always available. It's a good practice to check for stuff like that.

Please do not get confused about the wording I have used here. When talking about event listener callback, event listener callback function, event listener function or simply event listener I mean the same. They can be used as synonyms here.

Have a look at the Demo to see this example in action.

Comments
Removing event handlers without use of variable
posted by Jason
Wed Jan 06 15:48:27 UTC 2016
It's worth pointing out that most apps only have one intended press handler per button. If this is the case it's easy to detach an event via the mEventRegistry.press collection and avoid using a variable to store the event handler:
oBtn.detachPress(oBtn.mEventRegistry.press[0].fFunction);