Link to home
Start Free TrialLog in
Avatar of AlizaN
AlizaN

asked on

run ajax while loading page

I have an asp script that executes a sql statement that can take up to 2 minutes to complete.I would like to add a progress bar, and an accurate status display for the client. ("Updating records...Adding records...Creating report...")

I submit the page, and response.flush javascript that queries the database for the status. Then the page continues to run and executes the report. (while the client's javascript/ajax function has been started.)
The problem is that the ajax page doesn't return while the main page is sitting there loading the report.

I can run javascript, like appending text "please wait " before the page finishes loading but IE refuses to send ajax post/get while the main page is loading.

Any way around this? I tried loading the whole page,starting the javascript fetch, and then running the main execute through ajax too but that doesn't seem to work either.  

please advise.  
Avatar of Insoftservice inso
Insoftservice inso
Flag of India image

HI,
If you can copy paste the code . I can try to resolve ur issue.
Avatar of AlizaN
AlizaN

ASKER

Code is attached.  The main function is CheckActivityStatus() and everything goes from there. The code works fine if the javascript function doesn't attempt any ajax functionality (if it would just keep on appending to the text or something). it's the page that i'm calling via the xmlhttprequest that doesn't get returned till the page finishes loading. THANKS!!
<%@ Language=VBScript %>
<%
Response.Buffer = true	

set conn = server.CreateObject("adodb.connection")
conn.open sqlconnstr
%>
<HTML>
<HEAD>
<script language="javascript">
function createXMLHttpRequest() 
{

    if (window.ActiveXObject) 
    {
        xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
    } 
    else if (window.XMLHttpRequest) 
    {
        xmlHttp = new XMLHttpRequest();
    }
  
}

function GetServerSideResults(submitURL,onreadyfunction)
{
//var baseid = document.getElementById("slcBase").value;
//var facilityid = document.getElementById("hdnFacility").value;




		createXMLHttpRequest();
	
		xmlHttp.onreadystatechange = onreadyfunction;
		xmlHttp.open("GET", submitURL, true);
		xmlHttp.send(null);
}

function CheckActivityStatus()
{
								
								
	GetServerSideResults('cpoeCheckDCALLStatus.asp',RefreshActivityLog)
	setTimeout('CheckActivityStatus()',5000);
}

function RefreshActivityLog() 
{

    if(xmlHttp.readyState == 4) 
    {
        if(xmlHttp.status == 200) 
        {

							      
							   
										
			var options;
										
			var NewInnerHTML="";
			var TheResponse="";
			TheResponse = xmlHttp.responseText.substring(0,xmlHttp.responseText.length-1)
										
										
										
			document.getElementById("ActivityLog").innerHTML =TheResponse;
										
		}
									
	}
}
				
</script>
</HEAD>

<BODY>
<span id="ActivityLog" name="ActivityLog"></span>	



<script LANGUAGE="javascript">	
	CheckActivityStatus();
</script>
			
<% response.flush %>

<%
conn.execute "cpoeDCResident " & session("res") & "," & session("user") & ",'" & trim(dcreason) & "',1,0,'"& trim(idlist)&"','" & dndlist & "'"
conn.Close
set conn = nothing		
%>		
		
</BODY>
</HTML>

Open in new window

Avatar of HonorGod
Add something to function RefreshActivityLog() to show that it is actually being called, and with what status values...
I would probably add an empty div at the bottom of the page,
and add text to it each time the routine is called.
Avatar of AlizaN

ASKER

I did as you suggested and added to more spans called activitylog2 and activitylog3 to the page. updated them from CheckActivityStatus and RefreshActivityLog. (Attached the code again.)  CheckActivityLog just appends an "a" (just to see if it's entering it). RefreshaCtivityLog appends the readyState. They both append, but RefreshActivityLog only displays a readystate of 1. As soon as the pageload finishes it starts displaying a readystate of 2,3,4 (and completes the function by returning the actual data from the ajax page).  
<%@ Language=VBScript %>
<%
Response.Buffer = true	

set conn = server.CreateObject("adodb.connection")
conn.open sqlconnstr
%>
<HTML>
<HEAD>
<script language="javascript">
function createXMLHttpRequest() 
{

    if (window.ActiveXObject) 
    {
        xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
    } 
    else if (window.XMLHttpRequest) 
    {
        xmlHttp = new XMLHttpRequest();
    }
  
}

function GetServerSideResults(submitURL,onreadyfunction)
{
//var baseid = document.getElementById("slcBase").value;
//var facilityid = document.getElementById("hdnFacility").value;




		createXMLHttpRequest();
	
		xmlHttp.onreadystatechange = onreadyfunction;
		xmlHttp.open("GET", submitURL, true);
		xmlHttp.send(null);
}

function CheckActivityStatus()
{
								
	document.getElementById("ActivityLog2").innerHTML =document.getElementById("ActivityLog2").innerHTML  + 'a';							
	
	GetServerSideResults('cpoeCheckDCALLStatus.asp',RefreshActivityLog)
	setTimeout('CheckActivityStatus()',5000);
}

function RefreshActivityLog() 
{
	document.getElementById("ActivityLog3").innerHTML = document.getElementById("ActivityLog3").innerHTML+xmlHttp.readyState;
    if(xmlHttp.readyState == 4) 
    {
        if(xmlHttp.status == 200) 
        {

							      
							   
										
			var options;
										
			var NewInnerHTML="";
			var TheResponse="";
			TheResponse = xmlHttp.responseText.substring(0,xmlHttp.responseText.length-1)
										
										
										
			document.getElementById("ActivityLog").innerHTML =TheResponse;
										
		}
									
	}
}
				
</script>
</HEAD>

<BODY>
		AL1:	<span id="ActivityLog" name="ActivityLog"></span><br>
		AL2:	<span id="ActivityLog2" name="ActivityLog2"></span><Br>
		AL3:	<span id="ActivityLog3" name="ActivityLog3"></span>



<script LANGUAGE="javascript">	
	CheckActivityStatus();
</script>
			
<% response.flush %>

<%
conn.execute "cpoeDCResident " & session("res") & "," & session("user") & ",'" & trim(dcreason) & "',1,0,'"& trim(idlist)&"','" & dndlist & "'"
conn.Close
set conn = nothing		
%>		
		
</BODY>
</HTML>

Open in new window

>> can take up to 2 minutes to complete.
but you are sending a new ajax request every 5 seconds.
  >> GetServerSideResults('cpoeCheckDCALLStatus.asp',RefreshActivityLog)
  >> setTimeout('CheckActivityStatus()',5000);

that is just a recipe for chaos. If you want to leave setTimeout() where you currently have it, you need to send a SYNCHRONOUS request instead of ASYNCHRONOUS.  However, my guess is that you DO want an ASYNCHRONOUS request, in which case you need to call setTimeout() within refreshActivityLog at the end of the clause that checks for readyState=4.

Save the attached code as hielo.asp and try it:
<%@ Language=VBScript %>
<%
set conn = server.CreateObject("adodb.connection")
conn.open sqlconnstr
%>
<HTML>
<HEAD>
<script type="text/javascript">
var xmlHttp=null;
function createXMLHttpRequest() 
{
    if (window.ActiveXObject) 
    {
        xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
    } 
    else if (window.XMLHttpRequest) 
    {
        xmlHttp = new XMLHttpRequest();
    }
return xmlHttp;
}

function GetServerSideResults(submitURL,onreadyfunction)
{
	//var baseid = document.getElementById("slcBase").value;
	//var facilityid = document.getElementById("hdnFacility").value;
	if( !createXMLHttpRequest() )
	{
		alert("Please upgrade your browser")
		return false;
	}
	xmlHttp.onreadystatechange = onreadyfunction;
	xmlHttp.open("GET", submitURL, true);
	xmlHttp.send(null);
}

function CheckActivityStatus()
{
	document.getElementById("ActivityLog2").innerHTML +=' * ';       
	GetServerSideResults('cpoeCheckDCALLStatus.asp',RefreshActivityLog);
}

function RefreshActivityLog() 
{
	switch(xmlHttp.readyState)
	{
		case 4: 
			if(xmlHttp.status == 200) 
			{
				var options;
				var NewInnerHTML="";
				var TheResponse="";
				TheResponse = xmlHttp.responseText.substring(0,xmlHttp.responseText.length-1)
				document.getElementById("ActivityLog").innerHTML =TheResponse;
			}
			xmlHttp=null;
			//not the request has completed, send a new request within 5 seconds
			setTimeout(CheckActivityStatus,5000);
			break;

        	default:
		        document.getElementById("ActivityLog3").innerHTML+=' '+xmlHttp.readyState;
        }
}
                               
</script>
</HEAD>

<BODY>
                AL1:    <span id="ActivityLog" name="ActivityLog"></span><br>
                AL2:    <span id="ActivityLog2" name="ActivityLog2"></span><Br>
                AL3:    <span id="ActivityLog3" name="ActivityLog3"></span>



<script LANGUAGE="javascript">  
CheckActivityStatus();         
</script>
<%
conn.execute "cpoeDCResident " & session("res") & "," & session("user") & ",'" & trim(dcreason) & "',1,0,'"& trim(idlist)&"','" & dndlist & "'"
conn.Close
set conn = nothing              
%>              
                
</BODY>
</HTML>

Open in new window

Avatar of AlizaN

ASKER

>> can take up to 2 minutes to complete.
>>>>but you are sending a new ajax request every 5 seconds.
Let me clarify: The process that's running through PAGELOAD (cpoedcresident, line 80) takes 2 minutes to finish. the ajax request (checkactivitystatus, line 77) should take a split second.  

But what you said makes sense anyway, not to set the timeout till the function finishes running. so i tried your code above, but since the ajax function doesn't return readyState of 4 till the main process finishes, it doesn't call itself again till the main process is complete.

Again, the AJAX function DOES NOT return a ready state of 4 until AFTER the main page load is complete. So although your point about not setting the timeout till it returns is valid, it doesn't really address the issue that it's NOT RETURNING. (ready state is staying at 1 till the page finishes loading.)

Thanks for your response, please advise further....

What are the conditions under which the ready state of 4 is returned?

Is it simply related to the inherent delay of the server side application processing the request?
Avatar of AlizaN

ASKER

yes.  as soon as the actual page load is complete, the ready state of 4 is returned.
I'm confused.  I thought that you indicated that the SQL query could take 2 minutes to complete.

I presume that the Ajax request that is returning the ready state of 4 is not an indication of the SQL query being complete, but something else entirely.

What does it represent?

Can that state/condition be used as the initiation of your progress indication?
Avatar of AlizaN

ASKER

let me try this one more time:
i have a page that works as follows. User navigates to a page in the application. User clicks "submit". Page then begins running a sql process that can take up to 2 minutes to run.  During that time, (while page is still loading),  I would like to display text to the user indicating what that process is up to. I flush some javascript to the page and do a "select" through an ajax call that retrieves status information about the aforementioned query. (This fetch takes a split second.)  Then I display that text on the page...while the main page is still loading with the original sql process.   So the ready state of 4 should be an indication that my SELECT query is complete. (and that is how it works once the page finishes loading.)  but for some reason ready state doesn't become 4 until the initial sql execution and page load is completed.  

is that clearer?
- I flush some javascript to the page and do a "select" through an ajax call that retrieves status information about the aforementioned query. (This fetch takes a split second.)

* So this is the Ajax call that is completing.  ok.

> but for some reason ready state doesn't become 4 until the initial sql execution and page load is completed.

* Ah.  ok.  I think I have it now.  Because the initial query issued by the Ajax call is to the application that initiates the SQL query, you aren't going to see the ready state of 4 (complete), until the SQL query returns.

  So, what you need to do is have the Ajax call be to an application that kicks off the select in the background, and is allowed to complete before the SQL query does.

Does that make sense?
Avatar of AlizaN

ASKER


>>... Because the initial query issued by the Ajax call is to the application that initiates the SQL query...

I don't understand that. because it's the same web application? that's the problem?


  >>So, what you need to do is have the Ajax call be to an application that kicks off the select in the background, and is allowed to complete before the SQL query does.

That sounds right.
Did you copy and paste what I posted or did you just modify your existing script? Notice that I did NOT use
Response.Buffer!
Avatar of AlizaN

ASKER

i copied and pasted and ran your script directly. but the whole thing doesn't work without response.flush because the javascript isn't rendered to the browser yet. added response.flush and got back to the initial problem.
then make this:
function createXMLHttpRequest() 
{

    if (window.ActiveXObject) 
    {
        xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
    } 
    else if (window.XMLHttpRequest) 
    {
        xmlHttp = new XMLHttpRequest();
    }
  
}

a generic function. Currently it is setting a global variable (xmlHttp) to an "ajax object". Instead declare it as 

var xmlHttp =null; 

within the function. Then at the global scope use two different variables to send two different ajax requests:
var http1=createXMLHttpRequest();//this is for the current ajax you have
var http2=createXMLHttpRequest();//this one is for the 2min sql query

make sure both are ASYNCHRONOUS

Open in new window

Avatar of AlizaN

ASKER

i did as you suggested - created 2 http variables and set them separately. #1 -  the main part of your suggestion is to make execute the main ajax through sql too. does that mean you don't think it's possible to do it the way i was doing it - main sql through the page load, and the select through ajax?  #2 - it didn't really help. i made sure both were asynchronous, going so far as to call them through setTimeouts. Once the long query starts the select does not go past a ready state of 1. it's the same behavior.  i've attached the code.

can we go back to this post:
  >>So, what you need to do is have the Ajax call be to an application that kicks off the select in the background, and is allowed to complete before the SQL query does.

What does that mean?
<%@ Language=VBScript %>

<HTML>
<HEAD>
<script type="text/javascript">
var http1 = createXMLHttpRequest()
var http2 = createXMLHttpRequest()

function createXMLHttpRequest() 
{
	var xmlHttp = null;
    if (window.ActiveXObject) 
    {
        xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
    } 
    else if (window.XMLHttpRequest) 
    {
        xmlHttp = new XMLHttpRequest();
    }
return xmlHttp;
}

function GetServerSideResults1(submitURL,onreadyfunction)
{
	//var baseid = document.getElementById("slcBase").value;
	//var facilityid = document.getElementById("hdnFacility").value;
	if( !createXMLHttpRequest() )
	{
		alert("Please upgrade your browser")
		return false;
	}
	http1.onreadystatechange = onreadyfunction;
	http1.open("GET", submitURL, true);
	http1.send(null);
}

function GetServerSideResults2(submitURL,onreadyfunction)
{
	//var baseid = document.getElementById("slcBase").value;
	//var facilityid = document.getElementById("hdnFacility").value;
	if( !createXMLHttpRequest() )
	{
		alert("Please upgrade your browser")
		return false;
	}
	http2.onreadystatechange = onreadyfunction;
	http2.open("GET", submitURL, true);
	http2.send(null);
}

function CheckActivityStatus()
{
	document.getElementById("ActivityLog2").innerHTML +=' * ';       
	GetServerSideResults1('cpoeCheckDCALLStatus.asp',RefreshActivityLog);
}

function RunReport()
{
	qs = "?res=<%=session("res")%>&user=<%=trim(session("user"))%>&dcreason=<%=trim(dcreason)%>&idlist=<%=trim(idlist)%>&dndlist=<%=trim(dndlist)%>"
	GetServerSideResults2('cpoedcallexecute.asp'+qs,EndReport)
			
}

function RefreshActivityLog() 
{
	switch(http1.readyState)
	{
		case 4: 
			if(http1.status == 200) 
			{
				var options;
				var NewInnerHTML="";
				var TheResponse="";
				TheResponse = http1.responseText.substring(0,http1.responseText.length-1)
				document.getElementById("ActivityLog").innerHTML =TheResponse;
			}
			http1=null;
			http1 = createXMLHttpRequest()
			//not the request has completed, send a new request within 5 seconds
			setTimeout(CheckActivityStatus,5000);
			break;

        	default:
		        document.getElementById("ActivityLog3").innerHTML+=' '+http1.readyState;
        }
}
    
function EndReport() 
{
	switch(http2.readyState)
	{
		case 4: 
			alert("completed");
			break;
			
	}
			
    
}                               
</script>
</HEAD>

<BODY>
                AL1:    <span id="ActivityLog" name="ActivityLog"></span><br>
                AL2:    <span id="ActivityLog2" name="ActivityLog2"></span><Br>
                AL3:    <span id="ActivityLog3" name="ActivityLog3"></span>



<script LANGUAGE="javascript">  
   
    
setTimeout(CheckActivityStatus,1000);
setTimeout(RunReport,2000);

</script>
            
                
</BODY>
</HTML>

Open in new window

What kind of system is being used on the server side?

In what kind of language are the server side applications written?

Have the client (JavaScript / Ajax) call server side application #1
Have server side application #1 invoke, or start server side application #2
Have server side application #2 perform the SQL select
Have server side application #1 complete, and return the ready status of 4 to the client side (JavaScript / Ajax) that initiated the call.

Does that help?
Avatar of AlizaN

ASKER

using windows server 2003, iis 6, asp, sql server 2000

what do you mean by server side application #1 and #2? 2 different websites?
In your JavaScript, you:

- Create an XMLHttpRequest object
- Specify the URL of the server side application to be called/invoked/executed
- Provide optional parameters
- Specify the callback routine
- "open" the request to the server side application (#1) specified in the URL.

This server side application is the one that causes status updates to be returned to the browser side callback routine (specified above).

Currently, you have this server side application.  It sounds, from your update, that is is most likely to be an ASP that currently executes the SQL select.

This application could either be re-written, or a new (server side) application could be written that "calls" or executes this application could be written.

Does this make sense?
Avatar of AlizaN

ASKER

correct,it is asp that executes the sql select.

>>This application could either be re-written, or a new (server side) application could be written that "calls" or executes this application could be written.
This is the part I'm not getting. what part of the application has to be rewritten? What do you mean by "new" server side application?  To be clear, the url of my page is "10.0.0.10/mywebsite/test.asp". this does the main page load. The ajax function calls "10.0.0.10/mywebsite/ajaxpage.asp".  ( status update).   So it's the same app, different pages.  is this a problem?
mywebsite/test.asp is the URL that specifies the application being executed.

This ASP contains the SQL call.
When this program completes, the ready status of 4 is returned to the JavaScript.

Here is a diagram of what happens:

Step
-----
  1. The client browser executes the Ajax call to your server application
       mywebsite/test.asp
  2. The server application executes the SQL select to the backend database
  3. The database performs the select (query)
  4. The query response is returned to the server side application.
  5. The application completes, and the "ready status" is returned to the Ajax client.
      Client   | Internet |           |
     (browser) |          |  Server   | Database
     --------- +          + --------- + ---------
 1.      *-------------------->  
 2.                           *------------>
 3.                                        ...
 4.                           <------------*
 5.      <--------------------*

Open in new window

What you need to do is change things.  I see 2 alternatives.

1. "rewrite" your server side application (mywebsite/test.asp), so that instead of performing the SQL select, it (somehow) executes, or initiates another server side application to perform this task.  This would allow this server side application to then complete (while the SQL select continues to execute in the background), and the "ready state" of 4 can be returned to the client that initiated the request.

2. Change your client side application to call a different server side application which actually calls the original server side application (mywebsite/test.asp) "in the background".  This "new" server side application could then "complete", thus causing the "ready state" of 4 to be returned to the client.

Does that make sense?
Avatar of AlizaN

ASKER

1. you mean like a new thread. i don't think that's possible in asp (i suppose i could fire off a sql job, that's about as mulithreaded as asp gets)
2.i don't understand the second one...the ajax is call on test.asp calls ajax.asp and is supposed to return to test.asp i don't know where i can do any more redirection.

 i think what we're saying is that i need a separate thread, right? one page can't deal with 2 return trips from the server in an asynchronous fashion.  which means i can't do this in asp. is that the bottom line?
ASKER CERTIFIED SOLUTION
Avatar of HonorGod
HonorGod
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of AlizaN

ASKER

Thank you so so much. Even though we didn't get to the answer i wanted i really appreciate ALL the time you put into trying to answer my question.
My pleasure.  Sorry that we couldn't get to where you wanted.

Good luck & have a great day.