Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Ajax In Action (2006).pdf
Скачиваний:
63
Добавлен:
17.08.2013
Размер:
8.36 Mб
Скачать

448CHAPTER 11

The enhanced Ajax web portal

11.5Adding Ajax autosave functionality

Using Ajax allows us to implement an autosave feature that can be fired by any event without the user knowing that it is happening. Normally, the user would have to click a button to force a postback to the server. In this case, we will be firing the autosave with the onmouseup event, which ends the process of dragging and resizing events. If we were to fire a normal form submission on the onmouseup event, the user would lose all of the functionality of the page, disrupting her workflow. With Ajax, the flow is seamless.

11.5.1Adapting the library

As we mentioned earlier, the code from JavaScript DHTML libraries is normally cross-browser compliant, which frees us from spending time getting cross-browser code to work correctly. If you look at the code in the external JavaScript file, AjaxWindow.js, you’ll see a lot of functionality (which we will not discuss here because of its length). There are functions that monitor the mouse movements, and one function that builds the windows. There are functions that set the position of the windows, and another function that sets the size. Out of all of these functions, we need to adapt only one to have our window save back to the database with Ajax.

Adapting the DHTML library for Ajax

The DHTML library functions for dragging and resizing windows use many event handlers and DOM methods to overcome the inconsistencies between browsers. The dragging and resizing of the windows is completed when the mouse button is released (“up”). Therefore, we should look for a function that is called with the onmouseup event handler in the AjaxWindow.js file. It contains the following code, which is executed when the mouse button is released:

document.onmouseup = function(){ bDrag = false;

bResize = false; intLastX = -1;

document.body.style.cursor = "default"; elemWin="";

bHasMoved = false;

}

In this code, a lot of booleans are being set to false to indicate that their actions have been canceled. The cursor is being set back to the default. The line that we need to change is the one where the elemWin reference is being canceled. At this point, we want to take the reference and pass it to another function to initialize our XMLHttpRequest object, in order to transfer the information to the server.

Adding Ajax autosave functionality

449

 

 

Although sometimes when we adapt libraries, it might take a lot of trial and error to adapt them to our needs, in this case, the functionality is pretty straightforward. Just add the following line, shown in bold, to your document’s onmouseup event handler:

document.onmouseup = function(){ bDrag = false;

bResize = false; intLastX = -1;

document.body.style.cursor = "default";

if(elemWin && bHasMoved)SaveWindowProperties(elemWin);

bHasMoved = false;

}

The bold line in the previous code snippet checks to make sure that the object has been moved or resized and that the element still exists. If the user did not perform either of these actions, then there would be no reason to send the request to the server. If one of these actions was performed, we pass the element reference to the function SaveWindowProperties(), which initiates the request to the server.

Obtaining the active element properties

After the user has moved or resized an element, we must update the server with the new parameters. The DHTML window library uses CSS to position the elements and to set their width and height. This means that all we have to do is obtain the database ID, the coordinates, and the size of the window. We can obtain the coordinates and size by looking at the CSS parameters assigned to the window that had focus. We then can take these new parameters and send them to the server to be saved in the database with Ajax (listing 11.10).

Listing 11.10 SaveWindowProperties() function

function SaveWindowProperties(){

 

 

winProps = "ref=" +

 

 

elemWin.id;

b Obtain window ID

 

 

winProps += "&x=" +

 

c Find

 

parseInt(elemWin.style.left);

 

 

window

winProps += "&y=" +

 

position

parseInt(elemWin.style.top);

 

 

winProps += "&w=" +

 

d Grab

 

parseInt(elemWin.style.width);

 

 

window size

winProps += "&h=" +

 

 

parseInt(elemWin.style.height);

 

e Call Settings function

Settings("saveSettings",winProps);

 

elemWin = "";

f Remove element reference

}

450CHAPTER 11

The enhanced Ajax web portal

As you can see in listing 11.11, we obtain the ID of the window bby referencing the window object. The ID that we obtained was assigned to the window when the library built it. When it assigns an ID, it appends win in front of the number from the database id column; we can see that by looking at the JavaScript code that is building the windows.

The x and y positions of the window are obtained c by referencing the left and top properties in the stylesheet. We also use the stylesheet properties to obtain the size dof the window by referencing its width and height properties.

After obtaining the information, we can call another function, Settings() e, which we will be creating shortly, to send our request to the server. Once we call the function, we should remove the element object from our global variable elemWin f. To do this, we assign an empty string to the variable elemWin. Now with the SaveWindowProperties() function complete, we can initiate our silent Ajax request to the server with the JavaScript function Settings().

11.5.2Autosaving the information to the database

Ajax lets us send information to the server without the user even knowing it is happening. We can see this in action with two projects in this book. We can easily submit requests to the server as a result of both monitoring keystrokes, as we do in the type-ahead suggest (chapter 10), and monitoring mouse movements, as we do in this chapter. This invisible submission is great for developers since we can update the user’s settings without him having to lift a finger. In most cases, reducing steps increases the user’s satisfaction. For this application, the action of the user releasing the mouse button is all we need to initiate the XMLHttpRequest object. Now it’s time to initiate the process to send the request to the server.

The client: sending the silent request

The XMLHttpRequest process in this case will not require anything sophisticated. The user’s interaction with the form sends all of the form properties to our function. We first need to initialize the XMLHttpRequest object:

function Settings(xAction,xParams){ var url = xAction + ".servlet"; var strParams = xParams;

var loader1 = new net.ContentLoader(url, BuildSettings, ErrorBuildSettings, "POST",

strParams);

}

Adding Ajax autosave functionality

451

 

 

For the function Settings(), we are passing the action string that contains all of our window’s properties. We attach the parameters that we’re going to post back to the server. If we get a successful round-trip to the server, the loader will call the function BuildSettings(). If we get an error during the round-trip, we will call the function ErrorBuildSettings():

function BuildSettings(){

strText = this.req.responseText; document.getElementById("divSettings").innerHTML = strText;

}

function ErrorBuildSettings(){

alert('There was an error trying to connect to the server.'); document.getElementById("divSettings").style.display = "none";

}

The function BuildSettings() shown here is quite basic; all we are doing is finishing up our XMLHttpRequest received from the server. We can set a message on the portal status bar to show that we have updated the information on the server. We can add an error message to the status bar if we encounter a problem updating the information on the server. We also generate an alert, which tells the user of the error, but will also disrupt their workflow. We presented produc- tion-ready notification mechanisms in chapter 6, and leave it as an exercise for the reader to integrate those systems into the portal. Now let's see what happens on the server.

The server: gathering information from the client

All we have left to do is to extract the values from our form submission. The values were sent by our XMLHttpRequest object, which was triggered by the onmouseup event handlers. We need to create our SQL query with this information and update the record in the database to save the new information. We define an UpdateServlet for this purpose, which is shown in listing 11.11.

Listing 11.11 UpdateServlet.java (mapped to 'saveSettings.servlet')

public class UpdateServlet extends HttpServlet { protected void doPost(

HttpServletRequest request, HttpServletResponse response

)throws ServletException, IOException{

String windowId=

 

b Get unique ID from request

request.getParameter("ref");

HttpSession session=request.getSession();

PortalWindow window=(PortalWindow)

(session.getAttribute

c Get Window object from session

("window_"+windowId));

window.setXPos(getIntParam(request,"x"));

452

CHAPTER 11

 

 

 

The enhanced Ajax web portal

 

 

 

window.setYPos(getIntParam(request,"y"));

 

window.setWidth(getIntParam(request,"w"));

 

window.setHeight(getIntParam(request,"h"));

 

DBUtil.savePortalWindow(window);

d Save changes

 

Writer writer=response.getWriter();

 

Return simple text reply

 

writer.write("Save Complete");

 

 

 

 

 

 

writer.flush();

 

 

}

private int getIntParam(HttpServletRequest request, String param) { String str=request.getParameter(param);

int result=Integer.parseInt(str); return result;

}

}

Given the window ID as a request parameter b, we can extract the PortalWindow from session c and update its geometry based on further request parameters. We then call another method on our DBUtil object to save the portal window settings in the database d. Again, the implementation that we’ve provided here in listing 11.12 has been written to be simple and easy to translate to other languages.

Listing 11.12 savePortalWindows() method

public static void savePortalWindow(PortalWindow window){ Connection conn=getConnection();

int x=window.getXPos(); int y=window.getYPos(); int w=window.getWidth(); int h=window.getHeight(); int id=window.getId();

String sql="UPDATE portal_windows SET xPos="+x +",yPos="+y

+",width="+w

+",height="+h

+" WHERE id="+id; try{

Statement stmt=conn.createStatement(); stmt.execute(sql);

stmt.close();

}catch (SQLException sqlex){

}

}

The code in listing 11.12 is very straightforward. We read the relevant details from the PortalWindow object and construct a SQL update statement accordingly. Rather than returning any JavaScript this time, we issue a simple text acknowledgment.