I have a page which clients sometimes leave open for extended periods of time without refreshing (over 24hrs). Some of the actions on that page require valid PHP session so I have built a simple set of functions to run this check every 10 minutes.
2 Functions:
checkLogin()
refreshTimer()
We call checkLogin() to start, checkLogin() calls refreshTimer(). After timer completes it should call checkLogin(), which should call refreshTimer() and start the process all over again.
The first time we call checkLogin() directly things works great. However, when refreshTimer() tries to call checkLogin() I get a "function not defined" error for checkLogin().
From my research it looks like I should be able to call the checkLogin() without passing it to the refreshTimer().
I'm sure I'm probably missing something obvious. Thanks for your help!
function checkLogin()
{
$.ajax({
url: "/mysite.com/dev/includes/check_login_helper.php",
success: function(logged_in)
{
if(logged_in == "false")
{
// they are logged out - redirect them to login page
alert("logged out");
}
}
});
refreshTimer();
}
function refreshTimer()
{
var t = setTimeout("checkLogin()",15000); // do each 10 min currently shorter for test
}
//start the process up
checkLogin();
Fixed & using checkInterval
function checkLogin()
{
$.ajax({
url: "/mysite.com/dev/includes/check_login_helper.php",
success: function(logged_in)
{
if(logged_in == "false")
{
// they are logged out - redirect them to login page
alert("logged out");
}
}
});
}
setInterval(checkLogin(),15000); // do each 10 min currently shorter for test
Don't pass a string to setTimeout; it'seval in disguise. There is also no reason to capture the value returned by setTimeout in this case.
function refreshTimer()
{
setTimeout(checkLogin, 15000);
}
var t = setTimeout("checkLogin()",15000);
needs to be
var t = setTimeout(checkLogin,15000);
this method accepts functions and not strings.
Related
I'm using angular-http-auth for intercepting 401 response in order to display login dialogue and when the user is authorized, to retry failed request.
Since I'm using infinity-scroll I'm increasing an offset value, with every additional upload:
var upload = function () {
dataResource.query($scope.model).then(function (result) {
angular.forEach(result.items, function (value) {
$scope.items.push(value);
});
});
}
$scope.uploadMore = function () {
$scope.model.Offset = $scope.model.Offset + 10;
upload();
};
upload();
When my page loads up it immediately sends 2 request to server upload(), invoked from this directive, and uploadMore() by infinity-scroll.
However, after user has logged in, the page does not display the first 10 entries, instead it displays 11-20 items 2 times in a row.
When I tried to debug it, I noticed that when angular-http-auth retries requests it uses increased by 10 Offset value for both queries($scope.module argument).
Functions upload() and uploadMore() are running for 2 times before angular-http-auth, so I guess that is why interceptor uses updated argument for both queries.
Could somebody please help me with this problem?
So you can resolve this problem prevent execute request until previous will finish.
The faster way to do that is :
var pending = false;
var upload = function () {
if(!pending) {
pending = true;
dataResource.query($scope.model).then(function (result) {
pending = false;
angular.forEach(result.items, function (value) {
$scope.items.push(value);
});
});
}
}
I have a requirement where I need to poll the database via ajax from js to check for a status. If the status is "active" then the polling should stop and an alert should popup "case is now active". The js should check the db every 2 seconds until the db status returns "active." Can you provide an elegant js routine for this? Here's some general js to show what I want to do:
function ReportAsActivePoll()
{
for(var i=0; i<10; i++)
{
setTimeout(StatusIsActive,(i*2000));
if(statusIsActive)
{
ReportAsActive();
break;
}
}
}
var statusIsActive = false;
function StatusIsActive(case)
{
statusIsActive = GetStatusFromDB(case) == "active";
}
function ReportAsActive()
{
alert("case is now active")
}
A few notes:
I know the code above is not correct. It's just for illustrative purposes.
The code above will call StatusIsActive 10 times. I would like the calls to stop/break/discontinue after status is active. However, I think polling requires to queue up all the calls ahead of time so I'm not sure how to achieve this.
Use setInterval() and clearInterval() for simplicity. Like so:
<script type="text/javascript">
function checkStatus(theCase) {
var intervalId = window.setInterval(function() {
if (getStatusFromDb(theCase) == 'active') {
clearInterval(intervalId)
reportAsActive()
}
}, 2000)
}
function reportAsActive()
{
alert("case is now active")
}
var tmpCounter = 0
function getStatusFromDb(theCase)
{
if (tmpCounter++ == 4) return "active"
}
checkStatus('case 123')
</script>
You should also consider making functions start with a lowercase letter, because that is the normal JS convention. By choosing another style, you risk having case-sensitive errors that are annoying to track down.
You need to use setInterval instead of your setTimeout and when you received a valid response you have to remove this interval with clearInterval.
So you need to do something like this
var intervalID = window.setInterval(function(){
var resFromYourDB = ...; // get your result via ajax
if (resFromYourDB['active']){
window.clearInterval(intervalID);
// do you alert
}
}, 2000)
This way it will be polling your server till it will get active as a response and not a predefined amount of time as with setTimeout. Also when it will get this response it will properely stops.
Has anyone found that their javascript doesnt work, but when they step through the code it works fine ?
var cookie = getCookie('lusr');
var username = cookie;
if(!cookie){
$("#UserNav").load("loginform.html");
$("#loginbtn").click( function(){
var username = $("#usernametxt").val();
var password = $("#passwordtxt").val();
login(username,password);
});
}else{
$("#UserNav").load("user.htm");
$("#WelcomeUser").text("Welcome "+ username);
}
My issue occurs on this line :
$("#WelcomeUser").text("Welcome "+ username);
That's because load() is asynchronous: it returns right away, performs its work in the background, then calls a user-provided function when its task is complete. The stepping delay gives you the illusion that the function is synchronous and performs all its work before returning.
Therefore, you should pass a callback function to load() and perform your subsequent work inside that callback:
var cookie = getCookie("lusr");
if(!cookie) {
$("#UserNav").load("loginform.html", function() {
$("#loginbtn").click(function() {
var username = $("#usernametxt").val();
var password = $("#passwordtxt").val();
login(username, password);
});
});
} else {
$("#UserNav").load("user.htm", function() {
$("#WelcomeUser").text("Welcome " + cookie);
});
}
You are using the load() function which asynchronously fetches from the server. This means your form has not loaded by the time you go searching for its fields.
The reason it works when you step through is because it gives it time to load the form while you step.
You can use another version of load which has an asynchonous callback function, allowing you to provide functionality only to be called once the load is complete.
Check the jQuery docs for more info.
I have 2 functions: 1 checks that the user is logged in, and if he does - it calls for second function to get his userID. For now I'm just testing it with alert, to see if I do get the parameter.
This is the first function:
//Checking if the user is logged in or not
$(function(){
$.getJSON("inc/API.php", {command : "getUserName"},
function(result){
if(result==null){
$("#divGreeting").html("Hello, guest!");
$("#divLogin").hide();
$("#divUserOption").hide();
$("#divConnectOption").show();
}
else {
alert(getUserID(result));
$("#divGreeting").html("Hello, "+result+"!");
$("#divHeader").html("Hello, "+result+"! <a href='javascript:logout()'>Logout</a>");
$("#divUserOption").html("Hello, "+result+"! <a href='javascript:logout()'>Logout</a>");
$("#divConnectOption").hide();
$("#divLogin").hide();
$("#divUserOption").fadeIn(300);
}
});
});
And this is the second function, the one that should return the userID:
function getUserID(){
$.getJSON("inc/API.php",
{
command : "getUserID"
},
function(result){
alert(result);
return result;
});
}
The alert of the first function is undefined, while the alert of the second does have the userID. How come I can't return it's value to the first function? Why do I get `undefined?
Thank you!`
Ajax is asynchronous. You can't return a value from it.
What are are trying to do is akin to:
function foo() {
$('button').click(function () { return 1; });
}
var not_one = foo();
In this example, the value is not returned until the button is clicked (and it isn't the return value of foo anyway). With Ajax, the value is not returned until the HTTP response arrives.
You have to process the data in the callback function and not try to return to the calling function.
Try this:
//Checking if the user is logged in or not
$(function(){
$.getJSON("inc/API.php", {command : "getUserName"},
function(result){
if(result==null){
$("#divGreeting").html("Hello, guest!");
$("#divLogin").hide();
$("#divUserOption").hide();
$("#divConnectOption").show();
}
else {
getUserID(function(result) {
$("#divGreeting").html("Hello, "+result+"!");
$("#divHeader").html("Hello, "+result+"! <a href='javascript:logout()'>Logout</a>");
$("#divUserOption").html("Hello, "+result+"! <a href='javascript:logout()'>Logout</a>");
$("#divConnectOption").hide();
$("#divLogin").hide();
$("#divUserOption").fadeIn(300);
});
}
});
});
and then your getUserID function:
function getUserID(callback){
$.getJSON("inc/API.php",
{
command : "getUserID"
},
callback
}
EDIT
You said that you would need to use the username in a string concatenation context :
"Hello "+getUserName()+"!"
however, if it has to make an AJAX request every time, this is not possible unless a blocking,syncronous call is being used which is not a good practice at all. If you store the username in a variable when the page loads, you can just use the variable. if you want to still use a function that requests it every time it's used, it would have to be done something like this:
function getUserName(callback) {
$.getJSON("inc/API.php", {command : "getUserName"}, callback);
}
getUserName(function(result){
//do username processing here
});
The question title is rather vague, but here's my situation. I have roughly 700+ lines of jQuery for a web application, each function and "major point of interest" in the code noted by a log to the console when it fires. For example, I have a few functions that use an AJAX call to a servlet to retrieve some information. I log when the AJAX request begins, if it's succeeded (then print what data it gathered), etc. So, by the look of what my console has logged when I open the page, it seems to stop after the first AJAX call. Granted, the call seemed to work just fine, and the data it returned was perfect. As you'll see, it even populated the select box as intended. However, the console logs stop shortly after, making me believe that for some reason, the other functions are not being called...
jQuery
$(document).ready(function() {
Initialize();
});
function Initialize() {
console.log("Initializing...");
User();
Widgets();
if($.cookie("fogbugzId") != null) {
console.log("Stored ID: " + $.cookie("fogbugzId"));
$("#userSelect").val($.cookie("fogbugzId")).trigger("change");
$("#userSelect").hide();
} else console.log("No ID Stored!");
}
function User() {
console.log("Initializing User...");
$.each(FetchUsers(), function(index, user) {
$("#userSelect").append($("<option>").val(user.id).text(user.name));
});
$("#userSelect").change(function() {
if($("#userSelect").val() != "") {
console.log("User Changed to " + $("#userSelect").val() + ": " + $("#userSelect").text());
$.cookie("fogbugzId", $("#userSelect").val(), { expires: 365 });
}
Update();
});
console.log("User Initialized!");
}
function FetchUsers() {
console.log("Loading Users...");
$("#loading").show();
$.get(servlet, { command: "getUsers" }, function(data) {
var users = new Array();
$(data).find("user").each(function() {
users.push({
id: $(this).find("id").text(),
name: $(this).find("name").text()
});
});
$.each(users, function(index, user) {
console.log(">> " + user.id + ": " + user.name);
});
console.log("Users Loaded!");
return(users);
}, "xml").complete(function() {
$("#loading").hide();
}).error(function() {
console.log("Loading Users Failed!");
});
}
function Widgets() {
console.log("Initializing Widgets...");
// More Code
console.log("Widgets Initialized!");
}
Console
Initializing...
Initializing User...
Loading Users...
>> 267: Alex Molthan
>> 35: Bill Brinkoetter
>> 100: Bob Yoder
>> 189: Brian Cutler
>> 559: Brian Ormond
>> 400: Corey Nakamura
Users Loaded!
But the logging stops right there. So the AJAX call to fetch the users from the database works fine, but apparently the User() function doesn't manage to finish properly. The only error that the JavaScript console gives me is one within my jquery.min.js file:
Uncaught TypeError: Cannot read property 'length' of undefined jquery.min.js:16
f.e.extend.each jquery.min.js:16
User modifytime.js:14
Initialize modifytime.js:3
(anonymous function) modifyTime.jsp:21
f.extend._Deferred.e.resolveWith jquery.min.js:16
f.e.extend.ready jquery.min.js:16
f.c.addEventListener.B jquery.min.js:16
It looks as though it is breaking on the $.each() that iterates through the array of users returned by the FetchUsers() function. I know the function returns usable array, so I'm not sure what it's getting stuck on. Can anyone see something I'm missing right off the bat? I tried assigning the users[] returned by the FetchUsers() function into a variable first, then passing that into the $.each(), but it still didn't work. Any suggestions?
Edit: After replacing the minified version of jQuery with the uncompressed version, it seems as though the array of users that I pass into the $.each() function has now .length property, which is why it's breaking. Just to check, before I call that particular $.each() function, I placed a log of the users[].length returned from the FetchUsers() function to see that it still had no .length property. I then went to the FetchUsers() function itself and placed a log of the users[].length just before I return it. This log, however, works perfectly fine (though my example doesn't show it, it returns 40 users). So is my users[] not being returned as an array or something?
FetchUsers does not return anything, it does not even have a return statement. Additionally, $.get is an asynchronous function, so you cannot return the value it passes to its callback from the FetchUsers function. Instead, you could make FetchUsers take a callback it calls when it has received data of a user (and in this case doing that change would be relatively trivial):
function User() {
console.log("Initializing User...");
FetchUsers(function(user) { // Changed!
$("#userSelect").append($("<option>").val(user.id).text(user.name));
});
<...>
}
function FetchUsers(callback) { // Changed!
console.log("Loading Users...");
$("#loading").show();
$.get(servlet, { command: "getUsers" }, function(data) {
//var users = new Array(); No longer necessary.
$(data).find("user").each(function() {
callback({ // Changed!
id: $(this).find("id").text(),
name: $(this).find("name").text()
});
});
<...>
}
Changing those three lines with the "Changed!" comment should be enough to make it work correctly. (Though your logging of the users gotten will need to be slightly altered as they are no longer pushed into an array.)
I confess I have not read and understood every part of your source (nor checked if all the braces are closed), but FetchUsers clearly does NOT return anything (contrary to your claim) - so a call to FetchUsers() evaluates to 'undefined'. Fixing it will require some rewriting as in Javascript you cannot really return a result of asynchronous operation (like $.get) from a synchronous function (like FetchUsers()) - this would require multithreading (some kind of blocking, waiting etc).