Responding to the page unload in a managed bean
- by frank.nimphius
Though ADF Faces provides an uncommitted data warning functionality, developers may have the requirement to respond to the page unload event within custom application code, programmed in a managed bean. The af:clientListener tag that is used in ADF Faces to listen for JavaScript and ADF Faces client component events does not provide the option to listen for the unload event. So this often recommended way of implementing JavaScript in ADF Faces does not work for this use case. To send an event from JavaScript to the server, ADF Faces provides the af:serverListener tag that you use to queue a CustomEvent that invokes method in a managed bean. While this is part of the solution, during testing, it turns out, the browser native JavaScript unload event itself is not very helpful to send an event to the server using the af:serverListener tag. The reason for this is that when the unload event fires, the page already has been unloaded and the ADF Faces AdfPage object needed to queue the custom event already returns null. So the solution to the unload page event handling is the unbeforeunload event, which I am not sure if all browsers support them. I tested IE and FF and obviously they do though. To register the beforeunload event, you use an advanced JavaScript programming technique that dynamically adds listeners to page events. <af:document id="d1" onunload="performUnloadEvent" clientComponent="true"> <af:resource type="javascript"> window.addEventListener('beforeunload', function (){performUnloadEvent()},false) function performUnloadEvent(){ //note that af:document must have clientComponent="true" set //for JavaScript to access the component object var eventSource = AdfPage.PAGE.findComponentByAbsoluteId('d1'); //var x and y are dummy variables obviously needed to keep the page //alive for as long it takes to send the custom event to the server var x = AdfCustomEvent.queue(eventSource, "handleOnUnload", {args:'noargs'},false); //replace args:'noargs' with key:value pairs if your event needs to //pass arguments and values to the server side managed bean. var y = 0; } </af:resource> <af:serverListener type="handleOnUnload" method="#{UnloadHandler.onUnloadHandler}"/> // rest of the page goes here … </af:document> The managed bean method called by the custom event has the following signature: public void onUnloadHandler(ClientEvent clientEvent) { } I don't really have a good explanation for why the JavaSCript variables "x" and "y" are needed, but this is how I got it working. To me it ones again shows how fragile custom JavaScript development is and why you should stay away from using it whenever possible. Note: If the unload event is produced through navigation in JavaServer Faces, then there is no need to use JavaScript for this. If you know that navigation is performed from one page to the next, then the action you want to perform can be handled in JSF directly in the context of the lifecycle.