This dilemma is coming from a community member who was asked to put in a "confirm message" to a user where they had filled in information on a catalog item in the Service Portal and tried to move away from the page before "saving" it. We are talking about the same functionality as the one we have for the incident form.
So, we are looking at the page OOB "sc_cat_item" in the Service Portal.
This is what it looks like when selecting an item:
If I press back now or reload, the page will do so without saving the info I’ve put in.
We need to customize the widget that is showing the catalog item. First action is to clone the widget.
For those who don’t know, you can "CTRL+right click" on the widget to get a menu like the one below and easily go to the widget editor.
To be able to edit an OOB widget, we need to clone the widget first.
Select a new name and we are almost ready. Remember that when you clone, the cloned version doesn't load in the widget editor automatically.
Before we start we need to put our widget on the page to make it easier for testing and to avoid confusion when you think you’ve changed it later on. It is important to note that when you go to the page through designer mode, the widget is not visible, but it is there.
This can be a bit annoying, but there are different ways of removing it, for example by using page editor, like here:
What I do is just mark the whole container, delete it and then put in a new container, (a 12 "column") and put my widget in there. Then you can go back to your catalog page, reload it and when you "CTRL-right click" the new widget name should be visible.
And now, open up your widget in the editor and get ready for the real magic.
Do the following:
1. Add a name to the form that is holding the first. This is since angular is putting a variable on the form if it contains data that isn't saved and it's called $dirty. So if form-name.$dirty == true, it has unchanged data. I found on my world tour of Google some examples for angular to handle this, but couldn't get it to work. In this example I name the form "c.myCatTest". If naming it just "myCatTest" I couldn't get it to work, even if it should. Therefor the only change in the html template is on line 21:
2. Then we need to do some client script as well. You can put this pretty much where you want, but I choose between line 62 & 74:
Now, this is two parts. The $scope.$on('$locationChangeStart'.... should be enough if I read the docs correctly, but that triggers only if the user presses the back-button or presses on another link on the page, like breadcrumbs, menu etc.
I also tried to change my code on line 64 to if ($scope.myCatTest.$dirty) when I named my form to "myCatTest" but couldn't get it to work, so this works at least.
The second part $window.onbeforeunload.... is handled if the user is trying to write in a URL manually or hit the reload button.
It doesn't care about the back-button. So we need both.
With this code you now need to confirm if you have unsaved data when trying to leave the page.
Hope this will save some time for other people as well.
Links for more info:
$dirty -> https://docs.angularjs.org/api/ng/type/form.FormController
$locationChangeStart -> https://docs.angularjs.org/api/ng/service/$location
$windows.onbeforeunload -> https://developer.mozilla.org/en-US/docs/Web/API/WindowEventHandlers/onbeforeunload