Pages

Showing posts with label AJAX. Show all posts
Showing posts with label AJAX. Show all posts

Tuesday, November 1, 2011

Ajax in Strut 2 using XmlHTTPRequest


Ajax with Struts 2, I think I have had a good start with Struts 2. I was just toying around with what was provided in vaannila. It’s a real good stuff and in no time I got this idea of trying AJAX with Struts 2.


It took me some time though to understand how stuffs work with Struts.


Following is the fragment of struts.xml file that did the trick for me at last


            <action name="AjaxTest"  class="AjaxTest">
                     <result type="stream">
                           <param name="contentType">text/html</param>
                           <param name="inputName">inputStream</param>
                     </result>
              </action>


The class I Used to output the response is as follows


import java.io.InputStream;
import java.io.StringBufferInputStream;
import com.opensymphony.xwork2.ActionSupport;

@SuppressWarnings("deprecation")
public class AjaxTest extends ActionSupport  {
    private InputStream inputStream;
    public InputStream getInputStream() {
        return inputStream;
    }

    public String execute() throws Exception {
        inputStream = new StringBufferInputStream("Hello World! This is a text string response from a Struts 2 Action.");
        return SUCCESS;
    }
}


The javascript I used to perform the AjaxRequest is as follows
function triggerAjaxForExperiment()      {
       xmlHttp=new AjaxProcess("http://localhost:8080/myNewHelloWorld/AjaxTest.action",false);
       //initiate and asynchronous request to check whether the current reporthas any open chid documents
       xmlHttp.initiate();

       //this results in a boolean object isChildActive which is either true or false
       alert(xmlHttp.getHtmlFilteredResponseText())
}

About the AjaxProcess function that I have used here, it is a custom API I have created and can be found in the following location

And to your jsp file add the following line of html code to perform the test

       <input type="button" value="Ajax Experiment" onclick="triggerAjaxForExperiment()"/>

In the end what I got was as follows

It feels good to me J

Hope this helps you as well J

Saturday, October 15, 2011

Bugs: Ajax Caching issue in IE

Hats of to IE. It tests my mettle. Not a day goes by with out finding issues with IE one way or the other when I attempt to get some thing work the way I expect them to.
The good part is it helps me learn a lot from technology point of view as it is so different from other browsers and even simple things require a lot of work in IE.

Once an ajax request is created from the IE browser, it caches the same if it is a get request and this is absolutely absurd. I try getting a value through an Ajax request that varies frequently and because of this cache, I dont get the most recently updated value.

I have to restart the browser to get the recent value.

But with Post request, thank god, they are out of IE's caching issues. My saviour of the day is- AJAX POST REQUEST. This forces a fresh new request be triggered every time and the parameter that I provide are safer too.

Thursday, July 7, 2011

AJAX Post Request in Lotus Notes

Following is a short abstract of how you can create AJAX POST request.


One can always find a way to create an XMLHTTPREQUEST and many cross browser solutions are available across the internet. eg w3schools. So if leave the function call in the very first line for you to code.



var mypostrequest=new ajaxRequest()

//handle the response

mypostrequest.onreadystatechange=function(){

if (mypostrequest.readyState==4){

if (mypostrequest.status==200

window.location.href.indexOf("http")==-1){

//handle your response here

}

}

}

//open a post request

mypostrequest.open("POST", “your agent url", true);

mypostrequest.setRequestHeader("Content-type", "application/x-www-form-urlencoded");

//sample parameter

Var parameters = “label=value&process=post”

//send in the parameters to be processed in the lotus script agent

mypostrequest.send(parameters);

Wednesday, February 23, 2011

Issue : dojo.xhrGet fails in Safari

It was one trouble some situation when I found that my dojo.xhrGet failed in Safari. I felt like I was hanging in a cliff 500 feet deep. with no way back :( untill I stumbled upon the following forum discussion,

http://www.devcomments.com/cross-site-ajax-using-dojo-xhrGet-doesn-t-work-as-expected-but-at200443.htm

An amazing one. The first few posts are not visible for some reason but the vital ones that resolved the issue where visible.

The abstract of what I understood from issue that I faced and the discussion in this forum are as follows,

1. When using dojo.xhrGet, a preflight request get triggered from safari. And that means an Ajax request is triggered to the server before server authentication could occur. And this posed a severe security threat as Anonymous access to my Lotus Notes Database has to be enabled for dojo.xhrGet to work on Safari.

2. The trick was to use dojo.xhr instead of dojo.xhrGet . The documentation on  dojo.xhr can be found in the following location -http://dojotoolkit.org/api/dojo.xhr

3. The context that we need to understand here is that dojo.xhrGet({arguments}) is same as dojo.xhr("GET",{arguments}). And this is one of the vital points that resolved the issue

In addition to the above, to tackle the preflight request issue, it is better, if one can check on the play around with the "sync" flag. It is not that playing around with this will definitely resolve the issue but there are paucity of chances that it might help.

Hope this helps :)

Tuesday, January 11, 2011

Triggering lotus script agents and obtaining their response on the XPage using Server side javascript - An XMLHTTPRequest equivalent

Triggering agents from server side javascript in XPages is easy. How ever obtaining the response from the agents once the lotus script agent completes execution and displaying the same on the xpage was always a challenge to me. The following is a way helped me achieve it,

/***************************************************/
importPackage(java.net);
importPackage(java.io);

//create a url object by passing the lotusscript agent's url and ensure that you have some print statements in your agent
var agent:URL = new URL("Agent URL");
//create a connection with the agent's url provided
var agentConnection:URLConnection = agent.openConnection();
//open a buffered reader that gets the stream of response from the agent connection        
var inputReader:BufferedReader = new BufferedReader(new InputStreamReader(agentConnection.getInputStream()));
//read the output line by line and store them in a string
var res:String="";
while ((inputLine = inputReader.readLine()) != null) {
     res+=inputLine;
} 
//update the result to a output field on the XPage to view the same visually
getComponent("output").setValue(res);

/***************************************************/


This attempt was successful and I was able to recieve responses on the XPage but is a Synchronous way. Hence you may have to wait until the agent gets executed and the response is obtained.

Am yet to find the same to do in a Asynchronous way.

Hope this helps :)

Triggering lotus script agents and obtaining their response on the XPage using Client side javascript - An XMLHTTPRequest equivalent in Dojo

The traditional way through which we perform AJAX calls to lotusscript agents to obtain responses kept failing for me in XPages. I kept wondering why I was not able to get back any response from the agents.

The following dojo method though different, helped me accomplish the same,

/***************************************************/
      dojo.xhrGet( { // 
        url: "The url of your lotusscript agent", 
        handleAs: "text",
sync: true,
        timeout: 5000, // Time in milliseconds

        // The LOAD function will be called on a successful response.
        load: function(response, ioArgs) { 
         returnValue=response;
         alert(returnValue) ;  // this will alert your print statements from the lotusscript agent
        },

        // The ERROR function will be called in an error case.
        error: function(response, ioArgs) {  
          console.error("HTTP status code: ", ioArgs.xhr.status);
          returnValue= response;
          return returnValue; 
          }
        });
/***************************************************/

How ever I was not able to get the browser wait as I would do when using,
xmlHttp.open(GET,url,false)

The sync flag seems to work differently than I expected in the dojo.xhrGet method

Hope this helps :)

Monday, January 4, 2010

session.CurrentUserName in agentURL?OpenAgent

Have you ever tried to print the current user namen the browser by using a lotus script agent with a code say

   print session.currentusername

triggered by a javascript command say,

  location.href="http://servername/databasepath/agentname?openAgent"

What do you think will be printed on the browser?

Canonical form of the current user's name..!!!

No you will get the canonical name of the person or the server who has signed the agent

Yes thats true. And it did trouble me in my project. So How do you overcome it.

Scenario 1: put a computed text on the page or the form being displayed on the browser with the formula @username and ensure that it goes into a html field with some ID. You can always get the current user name using that htm field and pass it along with the agent url as a query string as mentioned below

  location.href="http://servername/databasepath/agentname?openAgent&userName="+document.getElementById('userNameField').value

Then in the lotus script agent you can obtain the query string and hence the user name

Scenario2 (The one I encountered):
The page being displayed on the browser is built by an agent you are not allowed to modify the same except for one single place and that is where I have to trigger my agent.

This issue was resolved through the following means.

Create a Page with the name userInfo.xml with content type set to other: text/xml.

<userInfo>
 <userName>
  <computed-text> with formula @username
 </userName>
</userInfo>

Now trigger a ajax request to this page,
obtain the response,
parse the xml and get the user name.

Now as mentioned in Scenario 1 pass this in the query string and do as necessary

Hope this is help ful

Thursday, December 24, 2009

What if @DBColumn Fails on web

There was one scenario in which I had to populate a combo box (drop down) which contains all the values in the first column of a view.

But the data in the view is so large that the formula itself failed. So I had to think of other work arounds to do the same.

I tried changing the "Number of lines to display in view" in the "Domino Web Engine" Tab from 1000 to 5000 in the server document. This resulted in an other error that caused my "openView?readviewentries" url to collapse and bomb an error. Probably 'cos of a heap over flow sort of thing.

So I required a more stable solution and hence arrived at a result. Many might feel that this one is quite inefficient as I do. The problem is if you have 50000 documents in that view, this code shall ask the browser to hit the server 50 times to get all the data as read view entries by default shall return only 1000 documents and since I have experienced it, I dont recommend changing it.

Please correct me if I am wrong

The following is a fragment of code that I developed to build the combo box.
It is not so generic and hence you may have to tweak it a bit to suit your requirements

/************************************/
var MAX_DOCS_IN_THOUSANDS=50; //This means you get up to 50000 options in your combobox

var comboBox="<select id='myComboID' onchange='javascript:myOnchangeEvent()'>";

//read view entries by default shall return xml entries of a maximum of 1000 documents
//hence loop through all the documents in the view in sets of 1000s and get all the company names
for (itr=1; itr<=MAX_DOCS_IN_THOUSANDS; itr++) { //start of for loop
startIndex=(itr-1)*1000+1;
try {
response=getViewColumn(DBServer,DBPath,viewName,startIndex);
} catch (error) {
info=" Probably the server name or the path of the database that you have mentioned is wrong </b>";
break;
}

var textNodes=response.getElementsByTagName("text");
try {
if (textNodes.length>0) {
for (jtr=0; jtr<1000; jtr++)
comboBox+="<option>"+textNodes[jtr].childNodes[0].nodeValue+"</option>";
} else {
break;
}
} catch(error) {
response=null;
textNodes=null;
break;
} finally {
response=null;
textNodes=null;
}
} //end of for loop
comboBox+="</select>";
/************************************/

/************************************/
//function to get the dolumn values from the view
function getViewColumn(serverName,databasePath,viewName,startIndex) {
var xmlHttp=xmlHttpRequest();
var url;

if (startIndex==-1) {
url="http://"+serverName+"/"+databasePath.replace(/\\/gi,"/")+"/"+viewName+"?readviewentries&count=-1";
} else {
if (typeof startIndex!='number') startIndex=0;
if (startIndex==0) {
url="http://"+serverName+"/"+databasePath.replace(/\\/gi,"/")+"/"+viewName+"?readviewentries&count=-1";
} else {
url="http://"+serverName+"/"+databasePath.replace(/\\/gi,"/")+"/"+viewName+"?readviewentries&start="+startIndex+"&count=-1";
}
}
var retValue
try {
var xmlHttp=xmlHttpRequest();
xmlHttp.open("GET",url,false);
xmlHttp.send(null);
retValue=xmlHttp.responseXML;
xmlHttp=null;
} catch (error) {
error.message += " <br>- in function getViewColumn(serverName,databasePath,viewName)<br>";
throw error;
}
return retValue;
}
/************************************/

/************************************/
//function to create sml http request
function xmlHttpRequest() {
var xmlhttp;
if (window.XMLHttpRequest)
{
// code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp=new XMLHttpRequest();
}
else if (window.ActiveXObject)
{
// code for IE6, IE5
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
else
{
throw new Error("Your browser does not support XMLHTTP! <br> - in function xmlHttpRequest()");
return;
}
return xmlhttp;
}
/************************************/

Tuesday, December 22, 2009

AJAX API

function AjaxProcess() { //start of class AjaxProcess


/*

* @Type : Class/Function

* @Name : AjaxProcess

* @Param : Mandatory -url - non empty url string

* @Param : Optional - typeOfOperation - boolean, true for synchronous process,and false otherwise - Defaults to false

* @Param : Optional - params - string, parameters to be sent via post request. Presence of this param will force a post request

* @Setter : setSource(newSourceURL)- To set the source for the ajax request

* @Setter : setAsynchronous(typeOfOperation)- To set the type of ajax request

* @Setter : setXMLResponse(xmlResponseFlag)- required to obtain xml response

* @Setter : setDebugFlag(debugFlag)- To help developers to check with

custom alerts with out affecting the flow

* @Property : initiate() - To initate the ajax request using an object of this class

* @Property : getResponse() - To get the response from the server using an object of this class

* @Property : getResponseText()- To get the text response from the server using an object of this class

* @Property : getHtmlFilteredResponseText - To get the html filtered text response from the server using an object of this class

* @Property : getResponseTable()- To get the table formated response from the server using an object of this class (special case will be rarely used when the server prints a html table as a response)

* @Property : rebuildRequest() - To re-initate the ajax request using an object of this class

* @Property : loadXMLString(textXml) - To load the given the xml string and convert the same into a xml document by parsing the same

* @Created : 13th, Oct'09

* @Author : Karthikeyan A

**/



var urlToProcess= arguments[0];

var opType=arguments[1];

var params=arguments[2];



var xmlHttpReq=null;

var ajaxResponse=null;



var isXMLResponse=false;

var isDebug=false;



/************Getters and Setters************************/

this.setSource= function(newSourceURL) {

if (typeof newSourceURL!="string") {

if (isDebug) alert("The param newSourceURL is not a string in function setSource(newSourceURL)");

newSourceURL=""

}

urlToProcess=newSourceURL;

}



this.setAsynchronous=function(typeOfOperation) {

if (typeof typeOfOperation!="boolean") {

if (isDebug) alert("The param typeOfOperation is not a boolean in function setAsynchronous(typeOfOperation)");

typeOfOperation=false;

}

opType=typeOfOperation;

}



this.setXMLResponse=function(xmlResponseFlag) {

if (typeof xmlResponseFlag!="boolean") {

if (isDebug) alert("The param typeOfOperation is not a boolean in function setXMLResponse(xmlResponseFlag)");

xmlResponseFlag=false;

}

isXMLResponse=xmlResponseFlag;

}



this.setDebugFlag=function(debugFlag) {

if (typeof xmlResponseFlag!="boolean") {

alert("The param typeOfOperation is not a boolean in function setDebugFlag(debugFlag)");

xmlResponseFlag=false;

}

isDebug=debugFlag;

}



/********* properties to be used by users***************/

//function to initate the ajax request using an object of this class

this.initiate = function() {

try {

//check for validity and re-initialize (if necessary) the parameters required for the class

if (typeof urlToProcess!="string") {

if (isDebug) alert("The param urlToProcess is not a string in function AjaxProcess(url,typeOfOperation)");

throw new SyntaxError("The param urlToProcess is not a string in function AjaxProcess(url,typeOfOperation)");

} else if (this.trim(urlToProcess)=="") {

if (isDebug) alert("The param urlToProcess is cannot be an empty string in function AjaxProcess(url,typeOfOperation)");

throw new SyntaxError("The param urlToProcess cannot be an empty string in function AjaxProcess(url,typeOfOperation)");

}



if (typeof typeOfOperation!="boolean") {

if (isDebug) alert("The param typeOfOperation is not a boolean in function AjaxProcess(url,typeOfOperation)");

typeOfOperation=false;

}



//create an xml http request

xmlHttpReq=this.xmlHttpRequest();



//if parameters- the thrid argument has been provided, force a post request

if (typeof params=="string") {

//mark the source and async type of the request

xmlHttpReq.open("POST",urlToProcess,opType);

//send request to server

xmlHttpReq.send(params);

} else {

//mark the source and async type of the request

xmlHttpReq.open("GET",urlToProcess,opType);

//send request to server

xmlHttpReq.send(null);

}



//get the response in text/xml format as desired (governed by the usXMLResponse flag)

if (!isXMLResponse) {

ajaxResponse=xmlHttpReq.responseText;

} else {

ajaxResponse=xmlHttpReq.responseXML;

}

} catch(error) {

//throw formated error messages in case of errors

error.message="API Error in method AjaxProcess(url,typeOfOperation).initiate(): -"+error.message;

throw error

}

}



this.getResponseXML=function() {

return xmlHttpReq.responseXML;

}



this.getResponseText=function() {

return xmlHttpReq.responseText;

}



if (!isXMLResponse) { //start of isXMLResponse if

this.getHtmlFilteredResponseText=function() {

var htmlFilteredajaxResponse=ajaxResponse.replace(/(<([^>]+)>)/ig,"");

htmlFilteredajaxResponse=this.trim(htmlFilteredajaxResponse, "\n");

return htmlFilteredajaxResponse;

}



this.getResponseTable=function() {

//To get the table formated response from the server using an object of this class

//(special case will be rarely used when the server prints a html table as a response)

var ajaxTableResponse=this.trim(ajaxResponse, "\n")

return ajaxTableResponse;

}

} //end of isXMLResponse if



this.rebuildRequest=function() {

xmlHttpReq=null;

ajaxResponse=null;

this.initiate();

}



this.recycle=function() {

xmlHttpReq=null;

ajaxResponse=null;

urlToProcess= null;

opType=null;

isXMLResponse=null;

}



/*****************Back end usage only****************************/

//function to generate a xmlhttprequest

this.xmlHttpRequest= function() {

var xmlhttp;

try {

if (window.XMLHttpRequest) {

// code for IE7+, Firefox, Chrome, Opera, Safari

xmlhttp=new XMLHttpRequest();

} else if (window.ActiveXObject) {

// code for IE6, IE5

xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");

} else {

throw new Error("Your browser does not support XMLHTTP! - in function xmlHttpRequest()");

return;

}

} catch(error) {

error.message="API Error in method AjaxProcess(url,typeOfOperation).xmlHttpRequest(): -"+error.message;

xmlhttp=null;

throw error

} finally {

return xmlhttp;

}

}



this.loadXMLString= function(textXml) {

var xmlDoc=null;

try {

if (window.DOMParser) { //firefox, Chrome, Opera, Safari

parser=new DOMParser();

xmlDoc=parser.parseFromString(textXml,"text/xml");

} else { // Internet Explorer

xmlDoc=new ActiveXObject("Microsoft.XMLDOM");

xmlDoc.async="false";

xmlDoc.loadXML(textXml);

}

} catch(error) {

//throw formated error messages in case of errors

error.message="API Error in method AjaxProcess(url,typeOfOperation).loadXMLString(textXml): -"+error.message;

//mark the return value

xmlDoc=null;

throw error;

} finally {

return xmlDoc;

}

}



//function to trim of leading and trailing spaces

this.trim=function(str, chars) {

return this.ltrim(this.rtrim(str, chars), chars);

}



//function to trim of white spaces on the left

this.ltrim=function(str, chars) {

chars = chars

"\\s";

return str.replace(new RegExp("^[" + chars + "]+", "g"), "");

}



//function to trim of white spaces on the right

this.rtrim=function(str, chars) {

chars = chars

"\\s";

return str.replace(new RegExp("[" + chars + "]+$", "g"), "");

}

} //end of class AjaxProcess