Tip

Run a Web agent on a JavaScript event using any browser

View member feedback to this tip.

This article is a "counterpoint" to Luke Leonhard's tip, Run a Web agent on any JavaScript event. . Luke demonstrates how you can run (using XML and Microsoft's XMLHTTP ActiveX component) an external agent from any JavaScript event and get results back without a screen refresh.

One of the downsides I noted in Luke's tip is the requirement of having to use a "browser specific" ActiveX component. The method demonstrated here (which I have employed on many applications) is browser agnostic, in that it uses standard Web technologies (providing your browser can support JavaScript and iFrames).

The basic logic is to have a form that contains an iFrame within it and an external process that can execute JavaScript in that iFrame. The iFrame must have some way of grabbing a handle to it (such as an ID), but can be easily set up to be transparent to the user as follows:

 <div style="display:none;">
 <iframe id="AgentWindow" 
height="50%" width="100%"
 frameborder="0" 
src=""></iframe>
 </div>

Now you can change the style on the div to make it "block" or "none" if you want to see the iFrame while coding and debugging, or eliminate the div completely and simply set the iFrame to a height/width to 0. Then use whatever method you choose to launch the agent by telling the agent to run in the iFrame window:

 function LaunchXtrnlAgent() {
  theObj = document.
getElementById("AgentWindow");
  if (theObj) {
   theObj.src = <URL2Agent +
 Parameters>;
  }
 }

The agent itself will perform whatever operations you wish and the results sent back from the agent will be placed in the iFrame. Then, using JavaScript methods that the agent generated as part of its results, you can make whatever changes are necessary (modifying JavaScript variables or even text) in the main window.

For complete details, try out the sample application listed below.

Instructions for sample application

The application first opens up a page that displays several fields and information. This page (that is really a simple Web form) and the "ProcessData" agent are the two workhorses of the example.

A user fills in the fields on the form and then clicks a button to perform an external operation. The external operation is launched by calling a LotusScript agent to perform some task (in this example taking two fields passed on the query string and performing a simple mathematical operation based on a third parameter passed) and then return results into an iFrame on the form.

The sample application uses one page and one agent. To run the example, create a Notes database on a Domino server capable of running Web applications. Create a page (the page name is not important) and set the page's "Web Access" content type to HTML. Paste the code listed below in that page.

Page content

<!DOCTYPE HTML PUBLIC "
-//W3C//DTD HTML 4.01
 Transitional//EN">
<html>
<head>

</head>
<body>

<form>
<h1>Test Page</h1>
(These are fields which the user 
will populate)<br>
Enter a Number here: 
<input name="FirstNumber" value=
""><br>
Enter a Number here: &
lt;input name="SecondNumber" 
value=""><br>
Select an operation here: 
<select name="Operation">
<option>+
<option>-
<option>*
<option>/</select>
<br>
<br>

(The agent, when finished will put 
the result of the operation here in a Text 
field)<br>
Result (from Agent): <input name=
"Result" value=""><br>
<br>
(The agent will also put other information 
here in a display only section)
<div id="ResultsContent">
The results will be placed here...
</div>

<script type="text/javascript">
/* The agent will ALSO modify the values 
of these paramaters */
var FirstNum = 0;
var SecondNum = 0;
var Operation = "";

var theFrame;

/* Here is the URL to the Agent computed
 as a relative URL */
var URL2Agent = "<Insert the URL to your 
application here>/ProcessData?
Open"

/* This method is called by the user 
clicking on the "Run" button */
/* It extracts values from the fields and
 passes them as query string 
parameters to the agent */
/* But you could also have the agent 
know what fields to examine and use them 
in various final javascript methods 
as well */
function PerformTest() {
n1 = document.forms[0].
FirstNumber.value;
n2 = document.forms[0].
SecondNumber.value;
op = document.forms[0].
Operation.options[document.forms
[0].Operation.selectedIndex].text;
url = URL2Agent + "&n1=" + n1 +
 "&n2=" + n2 + "&op=" + op;

/* Here is where we get a handle 
to the iFrame and run the Agent */
theFrame = 
document.getElementById("RunAgent");
if (theFrame)
theFrame.src = url;
}

/* This is a "Call Back" function
 which can be run by the agent when it's 
completed it's operation */
function CallBack() {
alert("Variables set by Agent" + 
"nFirst Num Var = " + FirstNum + "nSecond 
Num Var = " + SecondNum + 
"nOperation Var = " + Operation);
}
</script>
<br />
<input type="button" onClick=
"PerformTest();" value="Run">
<input type="button" onClick=
"CallBack();" value="Call Back">
<br /><br />Below here is an
 iFrame which will have the agent run 
in it.<br />
<div style="display:block;">
<iframe id="RunAgent" height="100%"
 width="100%" frameborder="0" 
src=""></iframe>
</div></form>
</body>
</html>

Next, create an agent in the application with the name "ProcessData," specify that the agent is a LotusScript agent and then paste the code below into the agent's "Declarations" section.

Agent content

Dim qsList As Variant
Const nl = |
|

Function Explode(Src As String, 
Delim As String) As Variant
Explode = Evaluate(|@Explode
("| & Src & |";"| & Delim &|")|)
End Function

Sub Initialize
Dim CurDoc As NotesDocument
Set s = New NotesSession
Set CurDoc = s.DocumentContext
Dim qs As String

' Extracts parameters from Query String
qs = CurDoc.Query_String(0)
qsList = Explode(qs, "&")

' Perform the operation on the variables
' THIS is what you want the agent to 
really do
n1 = Val(GetParam("n1="))
n2 = Val(GetParam("n2="))
op = GetParam("op=")
If op = "+" Then
rslt = n1 + n2
Elseif op = "-" Then
rslt = n1 - n2
Elseif op = "*" Then
rslt = n1 * n2
Else
If n2 <> 0 And n1 <> 0 Then
rslt = n1/n2
End If 
End If

' Put everything back into the main form

ResultString = |<h2>The 
Results = | & rslt & |</h2>|

' The agent returns back a document
 containing javascript which sets the js 
params and even text on the main form
Print(|<script type="text/javascript">|)
Print(|theObj = parent.document.
getElementById("ResultsContent"); | & nl )
Print(|theObj.innerHTML = | & |'| &
 ResultString & |';| & nl)
Print(|parent.document.FirstNum = 
"| & n1 & |";| & nl)
Print(|parent.document.SecondNum =
 "| & n2 & |";| & nl)
Print(|parent.document.Operation =
"| & op & |";| & nl)
Print(|parent.FirstNum = "| & n1 
& |";| & nl)
Print(|parent.SecondNum = "| & n2 
& |";| & nl)
Print(|parent.Operation = "| & op & 
|";| & nl)
Print(|parent.document.forms[0].
Result.value = "| & rslt & |"| & nl)

' This runs a "CallBack" method 
on the parent form. 
' You could even pass the name 
of this call back method on the query string 
and run that instead of hard 
coding the method name here
Print(|parent.CallBack();| & nl)
Print(|</script>| & nl)
End Sub

Function GetParam( param As String )
 As String
Forall x In qsList
pos = Instr(x, param) 
If pos > 0 Then
aStr$ = x
Params = Explode(aStr$, "=")
GetParam = Params(1)
Exit Function
End If
End Forall
End Function

From a Web browser, open the page you created and enter two values into the first two fields. Select an operation, and then click "Run" to launch the agent.

That's it. This is a very simple example but, by extension, the capabilities of using the method described here are limited only to your imagination.

Have fun.

MEMBER FEEDBACK TO THIS TIP

Thanks for your tip. I have actually used the method you speak of in your tip also, but I have found the ActiveX method to be advantageous in certain cases. The iFrame method, although supporting most new browsers, is asynchronous. As Amigoni had commented in my tip, Run a Web agent on any JavaScript event, many users have used setTimeouts to circumvent some of the issues. I used the agent to write back script, similar to what you are doing, but the asynchronous behavior can cause trouble.

Using the iFrame method you discuss, I implemented a document locking on Domino 6 (through the use of the onunload method). When using iFrames, the agent wouldn't always run. If I forced a JavaScript alert (simply saying "The browser is now closing..."), I could almost always guarantee it, but some users on dial-up connections still had difficulty. Changing to the ActiveX method allowed for the agent to run successfully every time, without the need for the JavaScript alert. Also, a few people have commented that they enjoy the ability to send multiple requests to the server at a time, and to do this using iFrames would require many hidden iFrames as a workaround.

But, you have a point. My solution was Internet Explorer specific. After I saw your tip, I decided to spend some time to research a cross-browser method that was synchronous. I came up with one, and submitted it back to SearchDomino. Check back to the ActiveX method to make an implementation of the synchronous method cross-browser compatible (tested on Netscape 6+, Internet Exploere 5+, Mac Safari and Firefox). For those of you who followed my previous tip, there are only minor modifications to make it cross-browser friendly.

Note: If users choose to use the iFrame method, however, I suggest adding iLayer tags to support legacy Netscape 4.x browsers...

<iframe id="AgentWindow" name=
"cwindow" frameborder="0" 
src=""></iframe> 
<ilayer height="" width="" 
id="iwindow"><layer id=
"AgentWindow" 
name="AgentWindow" src=
""></layer></ilayer> 

Note: The ActiveX solution does not work on Netscape 4.x, so Michael's tip should always be used if supporting that specific browser is critical.

—Luke L.

Do you have comments on this tip? Let us know.

This was first published in October 2004

There are Comments. Add yours.

 
TIP: Want to include a code block in your comment? Use <pre> or <code> tags around the desired text. Ex: <code>insert code</code>

REGISTER or login:

Forgot Password?
By submitting you agree to receive email from TechTarget and its partners. If you reside outside of the United States, you consent to having your personal data transferred to and processed in the United States. Privacy
Sort by: OldestNewest

Forgot Password?

No problem! Submit your e-mail address below. We'll send you an email containing your password.

Your password has been sent to:

Disclaimer: Our Tips Exchange is a forum for you to share technical advice and expertise with your peers and to learn from other enterprise IT professionals. TechTarget provides the infrastructure to facilitate this sharing of information. However, we cannot guarantee the accuracy or validity of the material submitted. You agree that your use of the Ask The Expert services and your reliance on any questions, answers, information or other materials received through this Web site is at your own risk.