Ajax in the .NET world without ATLAS (YUI instead)
So I took a quick stab at the ATLAS (asp.net ajax) framework, and I came away with the distinct impression that it is too much for too little. The biggest issue with AJAX in the .NET environment is that the fields you name on the back end have a different name on the front end, which complicates writing client side scripts. I get around that, and avoid the additional bloat, with a simple change in how I construct the ajax call.
A typical ajax call from a script, involves using the field names that the browser sees, pulling some values, calling an endpoint with those values as parameters, and working with the results. This gets complicated with .NET because .NET names its client side objects with a certain notation that denotes which naming container the field is in. This means that if you wanted to place your field names into your Javascript, then you would have to render the ASPX page, make note of the field names, and then hope you did not have to change the design and effect the field names.
Instead, how about we send the Javascript function the field names, and useout Prototype $F() function to get the values. To do this we need to use the “ClientID” property. The .NET framework knows what those field names are going to be when the page code is executing and ClientID is a programmatic way to make use of them. We simply set the onClientClick event of a button, to pass the ClientID’s of all the fields we need.
btnSave.OnClientClick = "updatePersInfo('" + txtAddress1.ClientID + "','" + txtAddress2.ClientID
btnSave.OnClientClick += "','" + txCity.ClientID + "','" + txtState.ClientID + "','"
btnSave.OnClientClick += txtZip.ClientID + "','" + txtHomePhone.ClientID + "');return false;"
When you so this with an ASP.NET button object, you need to end your call with a “return false” since all ASP.NET buttons default to POST actions, and we do not need that since we are doing AJAX call.
Then in our javascript function, we grab the field values with our Prototype $F() function, and send it to our ajax endpoint (I am using the YUI library since this project also has alot of modal dialog boxes, and I think the YUI dialogs are the best.)
function updatePersInfo(add1, add2, city, state, zip, homeph){
$("activityIcon").style.display = 'block';
var postData = "&add1=" + $F(add1) + "&add2=" + $F(add2) + "&city=" + $F(city) + "&state=" + $F(state) + "&zip=" + $F(zip) + "&homeph=" + $F(homeph) ;
var sUrl = "ajaxUpdate.aspx?reqType=10";
var request = YAHOO.util.Connect.asyncRequest('POST', sUrl, callback, postData);
}
var handleSuccess = function(o){
var domXML = o.responseXML;
var xmlDoc = domXML.documentElement;
$("activityIcon").style.display = 'none';
if(xmlDoc){
var jsTextTag = xmlDoc.getElementsByTagName("returnval")[0].attributes;
var jsText = jsTextTag.getNamedItem("value").value;
eval(jsText);
} else {
alert(o.responseText);
}
}
var handleFailure = function(o){
if(o.responseText !== undefined){
alert(o.responseText);
}
}
var callback = {
success:handleSuccess,
failure: handleFailure
};
On the AJAX endpoint side of things, I just pull those values from the POST stream, do some DB magic, and then return an XML stream with success or failure. (The killChars function is something I use to strip out SQL injection attempts).
Dim strEmpId As String = Session("empid")
Dim strAddress1 As String = killChars(Request.Form("add1"))
Dim strAddress2 As String = killChars(Request.Form("add2"))
Dim strCity As String = killChars(Request.Form("city"))
Dim strState As String = killChars(Request.Form("state"))
Dim strZip As String = killChars(Request.Form("zip"))
Dim strHomePhone As String = killChars(Request.Form("homeph"))
Dim strWorkPhone As String = killChars(Request.Form("workph"))
Dim strEmail As String = killChars(Request.Form("email"))
If dbMagic is successful Then
xDoc = returnSuccess(xDoc, "window.location.reload();")
Else
xDoc = returnFailure(xDoc, "alert('fix it!!'); ")
End If
Response.ContentType = "text/xml"
Response.Charset = "UTF-8"
'finish up
xDoc.Save(Response.OutputStream)
Private Function returnSuccess(ByVal xDoc As XmlDocument, ByVal returnVal As String) As XmlDocument
Dim childNode As XmlNode
Dim attNode As XmlNode
' start with the processing instructions
Dim nodeParent As XmlNode = xDoc.CreateNode(XmlNodeType.Element, "", "response", "")
Dim nodePI As XmlProcessingInstruction = xDoc.CreateProcessingInstruction("xml", "version='1.0'")
xDoc.AppendChild(nodePI)
childNode = xDoc.CreateNode(XmlNodeType.Element, "", "returnval", "")
attNode = xDoc.CreateAttribute("value")
attNode.Value = returnVal
childNode.Attributes.Append(attNode)
nodeParent.AppendChild(childNode)
xDoc.AppendChild(nodeParent)
Return xDoc
End Function
December 9th, 2006 at 1:02 pm
Hi,
Regarding getting the client id for .NET controls. That’s pretty simple in fact. In your script you can write something like:
var myInputText = document.getElementById('’);
December 9th, 2006 at 1:04 pm
Sorry
The blog system doesn’t HTML encode the comment right.
You should write inside the quuotes in getElementById(’’):
<:%= myTextBox.ClientID %>
December 9th, 2006 at 2:32 pm
That would work if you embedded the javascript into the ASPX page itself. But to allow my scripts to be used off of multiple pages, I need to place the javascripts into a separate file.
December 9th, 2006 at 4:40 pm
Totally agree.
The workaround this is to make a script tag in the same page, that only maps the generated IDs to variables with the same name of the original IDs (before adding the NamingContainer prefix); then later use these variable names from external files.
I don’t think external script files that use explicit ID names are good for use with multiple pages. I’d recommend either removing all the ID dependancies from them to use with multiple pages. Personally, I use external script with ID dependancies only as file per page, only toseparate them from the dynamic content of the page, so that the browser would cache them after the first call. While all the common script files are functions (many of them take IDs as parameters).
December 9th, 2006 at 5:25 pm
I think you missed the point of my method. I send the ClientId to the javascript function from within the ASP:Button onClientClick event. I never have to hard code any ID’s. Whether the functions are in an external file or not, this method works. Using global variables is not always a desirable method when you have a complex page with close to 100 different elements that may be sent to various javascript functions. Each button has all the needed references written into its onclick event. In one application alone I have over 14 javascript file references, and embedding them all into the ASPX page would create an organizational nightmare.
November 7th, 2007 at 5:56 am
killChars? That’s a code smell right there, sounds like mysql_real_escape if you get my drift. Tip: use parameterized commands to avoid injection, it’s taken care of for you.