I am using HostListener to detect when a user reloads or closes a browser window. The purpose is to #1 check if the current user owns the 'Is Being Edited' lock on the record, and #2 if so, call an observable to update the database. (Note: I have already implemented the lock system for navigation away from the component using CanDeactivate. The use of HostListener is for specifically reloading or closing the browser window).
According to this similar question, 'window:unload'
is a synchronous only event, therefore I can't use the asynchronous API call in the body of the host listener.
However, the accepted solution using XMLHttpRequest()
is being deprecated according to Mozilla.
Note: Starting with Gecko 30.0 (Firefox 30.0 / Thunderbird 30.0 / SeaMonkey 2.27), Blink 39.0, and Edge 13, synchronous requests on the main thread have been deprecated due to their negative impact on the user experience.
I need a solution that is more reliable. Is there a way to send a SYNCHRONOUS api call in Angular to work around this limitation? Or is there another way to make sure the API call completes before the browser is reloaded or closed?
// @HostListener allows guard against browser refresh, close, etc.
@HostListener('window:unload', ['$event'])
beforeUnloadHander($event) {
// Check if Is Being Edited must be removed
if (this.mustReleaseIsBeingEdited()) {
this.updateIsBeingEditedSub = this.updateIsBeingEdited$(true).subscribe(result => {
return true;
}, err => { console.error(err); }, () => { });
} else {
return true;
}
}
private updateIsBeingEdited$(isBeingEdited): Observable<boolean> {
const editedObj = {
_id: this.record._id,
IsBeingEdited: isBeingEdited,
EditedBy: this.accessLevelService.getUserId()
}
return this.httpService!.postData(
`records/_id/${editedObj._id}/IsBeingEdited/`,
editedObj
);
}
UPDATE
I am researching and may have found a possible solution with sendBeacon(). I am not sure how to implement this in Angular, or if it is a recommended practice. Any suggestions?
To solve this problem, analytics and diagnostics code have historically made a synchronous XMLHttpRequest call in an unload or beforeunload event handler to submit the data. The synchronous XMLHttpRequest blocks the process of unloading the document, which in turn causes the next navigation appear to be slower.
This is where sendBeacon() comes in. By using the sendBeacon() method, the data is transmitted asynchronously to the web server when the User Agent has an opportunity to do so, without delaying the unload or affecting the performance of the next navigation. This solves all of the problems with submission of analytics data: the data is sent reliably, it's sent asynchronously, and it doesn't impact the loading of the next page.