Search code examples
back-buttonsapui5

On Browser Back button handling of Hash URL change for SAPUI5/OpenUI5


We have SAPUI5 Shell placed at a div inside an index.xhtml page. When user modifies the data in our application, user can perform 3 types of action for navigating away from the application:

  1. Press the cancel button in our application
  2. Type some other URL in the browser address bar
  3. Press the back-button in the browser bar.

Our SAPUI5/Openui5 application works with the route concept (sap.ui.core.routing.Router) and hence the application has 'HASH URL'.

For 1 & 2, we made the following change and it works (based on Mozilla recommendation)

window.onbeforeunload = function(e) {
  var dialogText = 'Dialog text here';
  e.returnValue = dialogText;
  return dialogText;
};

Mozilla Recommendation - https://developer.mozilla.org/en-US/docs/Web/API/WindowEventHandlers/onbeforeunload

But for pt.3 - when user presses BACK BUTTON, the HASH URL changes. Based on other discussion on Stackoverflow, playing around with browser history or disabling the browser back button is not working with Browser/Web World.

Is there a way to do the following when browser back button is pressed:

  1. Show Popup giving user an option to Stay or Leave (informing changes in page will be lost)
  2. If user chooses to stay, then the URL remains including the 'HASH URL' part.

Solution

  • One possible way you can achieve this is by disabling the dispatching of the changed event from the Hasher plugin and handle the hashchange event yourself to prompt user with a confirmation message. You would want to make sure this is only done while your user is on the edit view in question and then re-enable the standard logic once user either clicks cancel, saves or confirms to navigate away.

    A rough example of this as follows...

    onInit: function() {
      this._hashHandler = (function(){
        var sCurrentHash;
    
        var fnHandleHashChange =function(e){
            var sOldHash = e.oldURL.substr(e.oldURL.search("#")+1);
            var sNewHash = e.newURL.substr(e.newURL.search("#")+1);
    
            if(sCurrentHash!==sOldHash){
                return;
            }
    
            if(confirm("Are you sure you want to navigate away?")){
                window.removeEventListener("hashchange",fnHandleHashChange);
                window.hasher.setHash(sOldHash.substr(1));
                window.hasher.changed.active=true;
                window.hasher.setHash(sNewHash.substr(1));
            } else {
                window.hasher.setHash(sOldHash.substr(1));
            }
        }
    
        return {
            startManualHashChangeHandling: function() {
                sCurrentHash = window.location.hash.substr(1);
                window.hasher.changed.active=false;
                window.addEventListener("hashchange",fnHandleHashChange);
            },
            stopManualHashChangeHandling: function() {
                window.hasher.changed.active=true;
                window.removeEventListener("hashchange",fnHandleHashChange);
            }
        };
      }());
    }
    

    ...so whenever you want to prevent user navigating without confirmation (so for example within a onEdit or onRouteMatched method) you can call...

    this._hashHandler.startManualHashChangeHandling();
    

    ...and then to disable the manual hash change handling (for example in your onCancel or onSave success method)...

    this._hashHandler.stopManualHashChangeHandling();