Tuesday, April 3, 2007

Step By Step AJAX

As i said earlier about my project Applying Leave thru online. I used that opportunity to learn AJAX also.

Requirement for AJAX in that project is, there is a user called Admin who has the rights to do the admin operations like add, modify and delete. What i did is links will be showed based on the designation of the user after successful login. Admin is the person to enable what are all the links to be shown to this designation. If Admin decides to remove a particular link to the designation, he has select the link from the assigned links and submit.

Assume that in Link removal page all the designation is showed in a combo box. By selecting a particular designation, page has to show the assigned links to this designation without refreshing the page.

Here is the code in JSP
<html:form action="removeRoleToDesignation">
<table width="50%" align="CENTER">
<tr>
<td width="36%"> Select Designation </td>
<td width="100%">
<html:select property="designationId" onchange="showRole(this.value)">
<html:option value="NA"> --select--</html:option>
<html:options collection="ALLDESIGNATION" labelProperty="designation" property="id"/>
</html:select>
</tr>
</table>
<div id="roleToRemove"> </div>
<table width="50%" align="CENTER">
<tr>
<td colspan="2" align="center" >
<html:submit styleClass="button"/>
</td>
</tr>
</table>
</html:form>


Here if user change the value it call the function showRole with current value as argument.

Here is the code for ShowRole Javascript function


var xmlHttp;
function showRole(str){
if(str == 'NA'){
document.getElementById("roleToRemove").innerHTML="";
}else{
var url="roleInfo?&desigId="+str+"&amp;amp;amp;amp;amp;amp;amp;ranid="+Math.random();
xmlHttp=GetXmlHttpObject(roleStateChanged)
xmlHttp.open("GET", url , true)
xmlHttp.send(null)
}
}


Here if user selected the --Select-- in Combo box then no roles need to display. So innerHTML set as empty.

In else condition i.e if user selects any one of the designation we have to send the request to fetch the assigned roles for this desingation from DB.

roleInfo is the servlet Mapping in web.xml and desigId is the selected value in combo box.

diffId is the one to differanciate the reqeust by sending the random number. If you are not using this there is a chance of getting the cached information from the browser.

var url="roleInfo?&did="+str+"&amp;amp;amp;amp;amp;amp;amp;diffId="+Math.random();

Javascript communicates with the server thru XMLHttpReqeust object.

xmlHttp=GetXmlHttpObject(roleStateChanged)

Here the code to get the XMLHttpRequest for various browsers..

function GetXmlHttpObject(handler){
var objXmlHttp=null
if (navigator.userAgent.indexOf("Opera")>=0) {
alert("This example doesn't work in Opera")
return
}
if (navigator.userAgent.indexOf("MSIE")>=0){
var strName="Msxml2.XMLHTTP"
if (navigator.appVersion.indexOf("MSIE 5.5")>=0){
strName="Microsoft.XMLHTTP"
}
try {
objXmlHttp=new ActiveXObject(strName)
objXmlHttp.onreadystatechange=handler
return objXmlHttp
}
catch(e){
alert("Error. Scripting for ActiveX might be disabled")
return
}
}
if (navigator.userAgent.indexOf("Mozilla")>=0){
objXmlHttp=new XMLHttpRequest()
objXmlHttp.onload=handler
objXmlHttp.onerror=handler
return objXmlHttp
}
}

Getting XMLHttpRequest is depend on the browser. so i have to use the same code for getting the XMLHttpRequest. The onreadystatechange function will process the response from the server

objXmlHttp.onreadystatechange=handler

here i am passing the roleStateChanged function as the handler to this GetXmlHttpObject function

xmlHttp=GetXmlHttpObject(roleStateChanged)

Here is the code for roleStateChanged function

function roleStateChanged(){
if (xmlHttp.readyState==4 xmlHttp.readyState=="complete") {
var ajaxReturn = xmlHttp.responseText;
if( ajaxReturn == 'NOROLE'){
document.getElementById("roleToRemove").innerHTML="";
document.laForm.designationId.options[0].selected = true;
alert('No Roles to Remove');
}else{
document.getElementById("roleToRemove").innerHTML=ajaxReturn;
}
}
}


look at this code if

(xmlHttp.readyState==4 xmlHttp.readyState=="complete") {

XMLHttpRequest Object has the property readyState. It explains the status of the response of server.

The followings are the possible statevalues
0 = The request is not initialized
1 = The request has been set up
2 = The request has been sent
3 = The request is in process
4 = The request is complete


XMLHttpRequest object has responseText property thru which we can get the information from the response.
var ajaxReturn = xmlHttp.responseText;

Look at the following line in showRole function
xmlHttp.open("GET", url , true)

this open method of XMLHttpRequest has 3 argument. the first one is used to define GET or POST method. second one is the actual URL where action takes place. Third one states that whether this request is executed asynchronusly ( true ) or not ( false ).


Now we will see what happened in the back end ( Servlet )

I have delegated the request from servlet.


public void findRoleByDesignation( HttpServletRequest request, HttpServletResponse response ) throws LASException {

/* Here getting the information passed from request */

String designationId = request.getParameter( "desigId" );
HttpSession session = request.getSession();

/* DesignationVO is the view class which has the setter and getter for Designation properties like id, desc....*/

DesignationVO designationVO = LASControllerFactory.getInstance().getController().getAllRoleByDesignation( new Long( designationId ) );

try{
/* Here writing the Html code in response writer. we can get these information thru XMLHttpRequest.responseText */
PrintWriter out = response.getWriter();
if ( designationVO != null ){

out.println( "<table width=\"50%\" "align=\"CENTER\">" );
out.println( "<tr>" );
out.println( "<td class=\"tdbgrigio\" width=\"36%\"> Enter Designation </td>" );
out.println( "<td class=\"tdbgrigio\" width=\"100%\"> " );
out.println( "<select name=\"roles\" multiple size=12 width=\"100%\">" );

session.setAttribute( "DESIROLETOREMOVE", designationVO );
Collection roleList = new ArrayList();
Set role2DesignationSet = designationVO.getRole2Designation();
Iterator it = role2DesignationSet.iterator();

while ( it.hasNext() ){
Role2DesignationDTO role2DesignationDTO = ( Role2DesignationDTO ) it.next();
roleList.add( role2DesignationDTO.getRole() );

out.println( "<option value=" + role2DesignationDTO.getRole().getId() + ">" + role2DesignationDTO.getRole().getDescription() + "</option>" );

}
out.println( "</select>" );
out.println( "</td>" );
out.println( "</tr>" );
out.println( "</table>" );

}
else{

/* If this designation id has no role to show then it will pass the message NOROLE to responseText. This is just for identification */
session.removeAttribute( "DESIROLETOREMOVE" );
out.print("NOROLE");
}

out.close();
}
catch ( IOException ioException ){
throw new LASException( ILASErrorCode.TECHNICAL_PROPLEM );
}
}

in roleStateChanged function,

var ajaxReturn = xmlHttp.responseText;
if( ajaxReturn == 'NOROLE'){
document.getElementById("roleToRemove").innerHTML=""; document.laForm.designationId.options[0].selected = true;
alert('No Roles to Remove');
}else{
document.getElementById("roleToRemove").innerHTML=ajaxReturn;
}

If response from the server returns NOROLE then i showed a alert box with No Roles to Remove information, else a multiple select box will appear with assigned roles as option values.

Getting the XMLHttpRequest is always same. There are lots custom tld's available in internet. Try with them. Keep in mind that AJAX is not an new technology... It is not a tough to learn... Good Luck.....


kick it on DotNetKicks.com

No comments: