I'm working on a chat and I'm trying to figure out how I can detect that the user has left the page or not. Almost everything is being handled by the database to avoid the front end from messing up.
So what I'm trying to do is once the page is left for any reason (window closed, going to another page, clicking a link, etc.) an ajax call will be fired before a person leaves so I can update the database.
This is what I've tried:
$(window).unload(function(){
$.post("script.php",{key_leave:"289583002"});
});
For some odd reason, it wouldn't work, and I've checked the php code, and it works fine. Any suggestions?
Try this:
$(window).unload(function(){
$.ajax({
type: 'POST',
url: 'script.php',
async:false,
data: {key_leave:"289583002"}
});
});
Note the async:false, that way the browser waits for the request to finish.
Using $.post is asynchronous, so the request may not be quick enough before the browser stops executing the script.
This isn't the correct way of doing this... Suppose the OS just hangs or something happens in the browsers process then this event wont be fired. And you will never ever know when the user has left, showing him/her online ever after he/she has disconnected. Instead of this, what you can do is.
Try connecting a socket so that you can know the user is disconnected when the socket is disconnected
You can send a request to the server (say after every 1 sec) so that you can know that the user is still connected. If you didn't receive the request - even after 2 secconds - disconnect the user.
Try to add popup (prompt("leaving so early?")) after $.post. It may work. Tho it may be bad user experience. :)
This is related to the answer above. https://stackoverflow.com/a/10272651/1306144
This will execute the ajax call every 1 sec. (1000)
function callEveryOneSec() {
$jx.ajax({}); // your ajax call
}
setInterval(callEveryOneSec, 1000);
The unload event is not recommended to detect users leaving the page. From MDN:
Developers should avoid using the unload event ... Especially on mobile, the unload event is not reliably fired.
Instead, use the visibilitychange event on document and/or the pagehide event on window (see links for details). For example:
document.addEventListener('visibilitychange', function() {
if (document.visibilityState === 'hidden') {
$.ajax({
type: 'POST',
url: 'script.php',
async:false,
data: {key_leave: "289583002"}
});
}
});
Better yet, use Navigator.sendBeacon, which is specifically designed for the purpose of sending a small amount of analytics data to a server:
document.addEventListener('visibilitychange', function() {
if (document.visibilityState === 'hidden') {
navigator.sendBeacon('script.php', {key_leave: "289583002"});
}
});
Related
I am trying to make.. "something" to know if an user is closing the browser or in other case is idle. I need to logout the user using a token.
I am using Symfony2.4 and actual logout include a handler because I need to know if the person is logged in another computer. I can't simple use a session expire because that handler will not execute and the application will still show the user as logged.
I am using this code and works really good!!
<script>
var unloaded = false;
$(window).on('beforeunload', unload);
$(window).on('unload', unload);
function unload(){
if(!unloaded){
$('body').css('cursor','wait');
$.ajax({
type: 'get',
async: false,
url: "{{ logout_url('main') }}",
success:function(){
unloaded = true;
$('body').css('cursor','default');
},
timeout: 50
});
}
}
</script>
The thing with this is that when the user try to go any link in the website this code execute and they need to log in again.
What can I do to avoid this code run by simply going to another link or what other thing can I do to have similar results?
This is more of a Javascript question, but well.
What about wrapping all your external links with javascript that sets a flag that disables your unload() function ? This is not very smart to do, though, but should work.
Something like that (not tested) :
$('a').click(function(){
// set the flag
myFlag = true;
return true;
}):
and in your unload :
function unload(){
if (myFlag) {
myFlag = false
return
}
// the rest here
}
EDIT :
If you want to send a request on page unload, it's better to use navigator.sendBeacon() as 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. See https://developer.mozilla.org/en-US/docs/Web/API/Navigator/sendBeacon
This question already has answers here:
Can the unload Event be Used to Reliably fire ajax Request?
(5 answers)
Closed 4 years ago.
I'm creating a queue-like page where only 1 person should be able to edit information about a specific database entry at a time.
Let's say a user is on page profile.php?id=1 - only the very first person who loaded this page should be able to make changes to it.
I've attempted to do this with JavaScript/jQuery, but am facing a problem.
On page load, I send an AJAX request to a PHP file that essentially sets a table cell to true for a specific ID. Then, I use a beforeunload event to set this cell to false when the page is unloaded. With this specific implementation, there is a problem though. The beforeunload event is either not fired when the tab is closed, or it is fired and the AJAX request does not have time to complete. This is a big problem because a user could potentially load up the page, see there is nothing to edit, and then close the tab without thinking about it, thus locking the page indefinitely until I reverse the lock in the database manually - and I would hate to have to force people to not use their browser the way they want to.
Here is my code:
$( document ).ready(function() {
var locked = <?=json_encode($data['in-review']);?>;
if(locked) {
$('input').attr('disabled', true);
$('#delete-model-button').attr('disabled', true);
$('#uidfield').attr('disabled', true);
$('#submitbutton').attr('disabled', true).text("This model is in review by another reviewer.");
} else {
$.ajax({
url: 'process/in-review.php',
type: 'POST',
data: {uid: $("#uidfield").val(), value: 1},
success: function (result) {
console.log("Model Locked in Review");
}
});
$(window).on('beforeunload', function() {
$.ajax({
url: 'process/in-review.php',
type: 'POST',
data: {uid: $("#uidfield").val(), value: 0},
success: function (result) {
console.log("Model Unlocked");
}
});
});
}
});
As you can see, if a user loads into a page that is already review locked, the beforeunload process is not called at all because that would allow users to unlock a form that another user may be working on.
How can I effectively unlock these pages if a user closes their tab or browser?
In case it matters, here is my in-review.php page:
<?php
include('db.php');
$uid = $_POST['uid'];
$value = $_POST['value'];
$db->run("UPDATE `devices` SET `in-review`=? WHERE `uid`=?", [$value, $uid]);
--EDIT:
This is commented as a duplicate question, but I disagree with this. That question is specifically asking "Can the unload Event be Used to Reliably fire ajax Request?" - I already know the answer to that is "Yes", because that is the method I am currently using, I also know it does not work at all for closing tabs/browser, therefore my question is not if this is a reliable method for what I want to do (I already know it is not), I'm asking for a different method that I can use to do this.
have you tried making a synchronous call of Ajax in beforeunload event?
i.e.
$(window).on('beforeunload', function() {
$.ajax({
url: 'process/in-review.php',
type: 'POST',
async: false,
data: {uid: $("#uidfield").val(), value: 0},
success: function (result) {
console.log("Model Unlocked");
}
});
});
The problem here is browser needs to keep connect alive with the server until the request is completed.
When the user clicks on other pages in your application that means connection to the server is alive and operation can be completed, and in case of browser/tab close connection to server is lost.
This might work on some situations i.e. your server was fast enough to respond before complete browser closure i.e. destruction in window object
I was reading this question: Trying to detect browser close event
But it's not comprehensive enough, or at least I'm not sure it is, I need to detect when the user leaves the website, this could be:
internet died
PC shuts down (power outage for example)
user close the browser
user close the browser tab in which the website was running
I'm sure there are more cases.
This probably needs to be managed by the server, and not some javascript event that is not going to be fired in extreme cases.
Any ideas what could be used in this case?.
You could use socket.io and listen for when the socket is lost, or you could have your site send a heartbeat to the server and if X milliseconds goes by without a pulse, you can assume the user left for any of the reasons you listed.
I am using Java Script to detect the event of leaving and sending an ajax request to my server so I can store that the user left the page.
The second part is to detect the time the user is in my page, every 3 seconds I also send a ajax request to my database to save the time of the user in the page.
<script>
window.onbeforeunload = function(){//If user left the page
user_left_page();
};
function user_left_page(){//USER LEFT THE PAGE send data to php to store into my database
var action = "left_page";
$.ajax({
url:"includes/track-page-time.inc.php",
method:"POST",
data:{ action: action},
success: function(data){
},
});
}
//This one below is to store the time the user is spending in your page. I am using both
// in my code, basically I keep storing the data every 3 seconds to know the time
setInterval(function () {
update_user_activity();
}, 3000);//Interval time to send the info to the database
function update_user_activity(){//IS USER IN THE PAGE?
var action = "update_time";
$.ajax({
url:"includes/track-page-time.inc.php",
method:"POST",
data:{ action: action},
success: function(data){
},
});
}
</script>
Another simple method you can track the IP/Session Id and save in the Database, you may update the time in the db using the ajax call in an interval i.e every 5 or 10 minutes.
if user not taken any activity and the time will not be updated, if time in db is less than the time() - $intervals , then you can assume that the user has left, lost connectivity etc.
You could use the window.onbeforeunload for the last two cases i.e. detecting the browser close or tab close event. For the first two events that is power failure or connectivity problems, only continuously ping or like AlienWebguy said the heartbeat mechanism can be implemented.
window.onbeforeunload = confirmExit;
function confirmExit()
{
return "You have attempted to leave this page. If you have made any changes to the fields without clicking the Save button, your changes will be lost. Are you sure you want to exit this page?";
}
Ref site
Is it bad practice to perform a redirection within an jQuery AJAX request?
$.ajax({
url: "myurl",
success : function(response) {
window.location.replace('MYNEWPAGE');
},
error: function (xhr) {
}
I'm experiencing some strange behaviour in an app and I think this is the issue.
location.replace() doesn't store the current page into the browser history, the user can't use the back button to go back onto the page. You should use location.assign(URL) or location.href = URL.
Should only use window.location.href = "whatever" to change the url. Note that this will cause you to postback your whole page, strange behavior may come from your load events on new page firing unexpectedly, including other ajax events that might also set window.location.href - you could theoretically get deadlock with stuff just continuing to send you to new pages (careful).
window.onbeforeunload = function() {
return $j.ajax({
url: "/view/action?&recent_tracking_id=" + $recent_tracking_id + "&time_on_page=" + getSeconds()
});
}
this what I have, but it returns an alert with [object Object]
how do I just execute the AJAX?
note: when I just don't return anything, the server doesn't show that it is receiving the ajax request.
You don't need to return anything, just fire the ajax call.
window.onbeforeunload = function(e) {
e.preventDefault();
$j.ajax({ url: "/view/action?&recent_tracking_id=" + $recent_tracking_id + &time_on_page=" + getSeconds()
});
}
If you are using jQuery, you can try binding to the .unload() event instead.
onbeforeunload allows you to return a string, which is shown in the 'Do you want to leave' confirmation. If you return nothing, the page is exited as normal. In your case, you return the jqXHR object that is returned by the JQuery ajax method.
You should just execute the Ajax call and return nothing.
Why are you returning the reference of function to global pool? It should be like this:
window.onbeforeunload = function() {
$j.ajax({
url: "/view/action?&recent_tracking_id=" + $recent_tracking_id + "&time_on_page=" + getSeconds()
});
}
To the best of my understanding, the onbeforeunload function will only return an alert. This was done to prevent the annoying popups of a few years back.
I was building a chat client a while back and the only way i could figure out to do something like this is to do a setInterval function that updated a timestamp, then checked for timed out users and removed them. That way users that didnt "check in" within a certain interval would be removed from the room by other users still logged in.
Not pretty, or ideal, but did the trick.
Doing standard ajax calls in a page unload handler is being actively disabled by browsers, because waiting for it to complete delays the next thing happening in the window (for instance, loading a new page).
In the rare case when you need to send information as the user is navigating away from the page (as Aaron says, avoid this where possibl), you can do it with sendBeacon. sendBeacon lets you send data to your server without holding up the page you're doing it in:
window.addEventListener("unload", function() {
navigator.sendBeacon("/log", yourDataHere);
});
The browser will send the data without preventing / delaying whatever is happening in the window (closing it, moving to a new paeg, etc.).
Note that the unload event may not be reliable, particularly on mobile devices. You might combine the above with sending a beacon on visibilitychange as well.