Introduction
I came forth to write this down because of my own frustration of having a hard time to find good sample codes to get me to where I wanted. Basically, I wanted my ASP.NET page, where I had a form for entering expense item, to do the following:
- When I click on a Save button on the form, I do not want post back as the post back would mess up with something on the form; not just do it for the sake of no post back. To implement that, I chose to use jQuery AJAX Post to send form data wrapped in JSON format to another ASP.NET page for processing. Yes, I could have simply used an
UpdatePanel
from the ASP.NET AJAX Controls Toolkit, but that was not what I wanted in this case.
- The AJAX processing page would retrieve the JSON data object and do the database update.
- Once the database update is done, the page would send a response text back to where the AJAX call was initiated and updates the front page.
My objective was quite simple, but it took me more time than what I thought would need to accomplish it. And the reason was simply because this time around, I was unable to find enough references to guide me through, so I had to spend a lot of time developing a solution via trial-and-error method. Therefore, once I came up with a solution, I told myself I needed to share this with others as I have benefited a lot in the past from the community by looking at other programmers' postings.
Access form element via the jQuery wildcard selector
The first challenge I encountered was to retrieve all form elements that were server bound – either a web control by itself or a web control inside a user control. The ClientID of web control could be used, but I did not like to mix too many server tags <%=var%>
with JavaScript, plus they might impede the JavaScript performance. Thankfully, the jQuery wildcard selector has made this easy and clean.
Here is an example of how this is done:
var recordid = $(“[id$=’txtRecordID’]”).val();
This will get me the text value in a server-side textbox control:
<asp:TextBox ID="txtRecordID" runat="server" Width="100px">
</asp:TextBox>
But what about a TextBox
in a Web User Control? That was what I used the wildcard for – to get to the element that has a client ID ending with a server control ID. Normally, if I simply place a TextBox
control on a web form, the client ID will exactly be the same as the ID I use in server side; in that case:
$(“#txtRecordID”)
will return the same element object as:
$(“[id$=’txtRecordID’]”)
But most of the time, we would group certain web controls on a User Control and then use the UserControl on a web form. In that case, $(“#txtRecordID”)
will get you nothing because now you have a user control ID added to the client ID for the TextBox
, so now, you will use the wildcard selector instead: $(“[id$=’txtRecordID’]”)
. To assure that the wildcard will return the unique element, you can add the User Control server ID to make it look like this:
$(“[id$=’ucMyControl_txtRecordID’]”)
(In some cases, you might have two or more server controls that are all named txtRecordID
, sitting in separate user controls that are embedded in the same web form, and then it is absolutely necessary that you add the user control ID into the jQuery wildcard search. I picked up this syntax for searching element endings with a specific server ID from the web community somewhere, sometime ago, but I was unable to locate the source again to give a reference URL here. But I did come across a similar post as of this writing at www.emadibrahim.com that was using wildcards for searching elements beginning with a specific ID, and the syntax looks like this: $(“[id^=pnl]).hide()
- hide all the div
s that start with “pnl” in their control IDs.
Send JSON-formatted data via jQuery AJAX
Now that I cleared the way to gain access to server side elements via the jQuery wildcard selector, I collected the data and stringed them into a JSON format. JSON is just another lightweight alternative of XML format, and here is my simplified version of the JSON data string:
var json=”{‘RecordID’:’” +
$(“[id$=’txtRecordID’]”).val() + “’,’ItemName’:’” +
escape($(“[id$=’txtItemName’]”).val()) + “’,’CategoryID’:’” +
(“[id$=’ddlCategories’]”).val() + “’}”;
I packed my form data into a JSON formatted string simply because I wanted to use the JSON.Net API tool to parse it later on at the other end of the wire. I used the “escape
” function in front of all text fields to encode any possible odd character such as an apostrophe that could throw the JSON parser off.
Next, I send the data via jQuery AJAX, using the syntax as below:
var to=”DataProcessor.aspx?Save=1”;
var options = {
type: "POST",
url: to,
data: json,
contentType: "application/json;charset=utf-8",
dataType: "json",
async: false,
success: function(response) {
},
error: function(msg) { alert(msg); }
};
var returnText = $.ajax(options).responseText;
Here, response
in the success section is the same as the responseText
returned from $.ajax
.
Retrieve JSON data from Request.InputStream
Then, I went into the DataProcessor.aspx code-behind and did the following steps to retrieve and parse the data:
- Check the Content Type of the
Request
object using this syntax:
if (Request.ContentType.Contains("json") &&
Request.QueryString["Save"]!=null)
SaveMyData();
- The function
SaveMyData
retrieves the JSON data by reading the InputStream
from the Request
object, as shown below:
System.IO.StreamReader sr = new System.IO.StreamReader(Request.InputStream);
string line = "";
line = sr.ReadToEnd();
Console.WriteLine(line);
At this point, the string variable line
contains a JSON formatted string, like:
"{'ItemName':'Steve%27s%20Demo%20Item','CategoryID':'1','RecordID':''}"
I could have created my own function to parse out this string and be done with it. But why should I re-invent the wheel while there is already something called JSON.Net out there? Surely, I found the needed API from http://james.networking.com and downloaded the library for the .NET 3.5 version. Following the instructions that came with the download, I added the Newtonsoft.Json.dll assembly to my project and imported the namespace Newtonsoft.Json.Linq
to the page class; then there it was – just one line of code to do the parsing:
JObject jo = JObject.Parse(line);
Once my JSON-formatted string variable, line
, was parsed, I accessed each property using the following code:
Console.WriteLine((string)jo["RecordID"]);
Console.WriteLine(Server.UrlDecode((string)jo["ItemName"]));
Remember, I did an escape
for ItemName
when I packed the form data into a JSON string in DataForm.aspx? Here, I did an equivalent of “unescape” using Server.UrlDecode
so the “%20” will return to space and “%27s” to “’s”, and so on. You don’t want to UrlDecode
before running the data downloaded from Request.InputStream
through the JObject
parser as some JSON unfriendly characters like an apostrophe (“’”) will blow the parser. So, only do UrlDecode
after JObject.Parse()
, and do it to each individual property of string type. Once the data is parsed, I process them in the data tier and return a record ID back to the front page simply by calling Response.Write()
. To simplify the demo, I did not include any database logic here; instead, I simply returned the “CategoryID” that was passed in the JSON string from the Category dropdown list on the front page to indicate if the database update was successful or failed:
Response.Write((string)jo["CategoryID"]);
This is what got me to jQuery.ajax(options).responseText
. You can also pack a long HTML string and shuffle it back to .ajax().responsText
to render on the front page.
Now, I returned to the front page and retrieved the responseText
as follows:
var returnText = $.ajax(options).responseText;
if (returnText > 0) {
$("[id$='txtRecordID']").html( returnText);
$("#divMsg").html("<font color=blue>Record saved successfully.</font>");
}
else {
$("#divMsg").html("<font color=red>Record was not saved successfully.</font>");
}
Summary
Putting them all together, here is how things moved: used the jQuery wildcard selector $(“[id$=’serversidecontrolid’]”)
to retrieve form data that is stored in server controls such as TextBox
and DropDownList
, constructed them into a JSON string, and then used jQuery.Ajax()
to POST JSON data to a different ASP.NET page for processing; downloaded the JSON data from the other side using a System.IO.StreamReader
to read off the Request.InputStream
object, then used the JSON parser API provided from JSON.Net to parse the JSON data string into a JObject
. Once the data is saved, we use Response.Write
to return the result to the front page.
I was satisfied with this light weight solution that helped me get rid of the heavy foot-printed ASP.NET AJAX UpdatePanel
to overcome the page postback. My goal of writing this paper, also my first ever article for CodeProject, was to share my research and connect pieces so others will not have to repeat the frustration I experienced when I first started it and could only find a piece here and a piece there.