By Brian, 2 years and 4 months ago

Classic ASP and AJAX

There aren't many tutorials on the web for Classic ASP and AJAX interfaces. Classic ASP is just about fazed out at most companies, but there are still plenty of legacy applications that use it. There is a lot of confusion about AJAX and what it is. Mainly, it is a client-side application that sends data to a back end parser, and thus the back-end processor can be written is anything from asp to cfm to php to old-school perl cgi's.

First and foremost, AJAX is VERY easy. Get it over your head that it's complicated because its not.

Now, let's get to it.
I was faced with the problem of performing a city and state look up based off entered zipcode.
This is a simply database pull, but because the zipcode is like the 5th thing asked, and theres more after it, it doesn't make sense to go through a page reload process.

AJAX to the rescue.

AJAX uses 3 «sides» to make it happen.

  • HTML form or something along these lines
  • JS scripting to pass the http request
  • server-side script or some other processor to return data when its called.

First, grab this javascript function set. This can be found on just about every AJAX app or tutorial out there. I have added some tweaks to fit our application here.

  1. var xmlHttp;
  2. var rootpath;
  3.  
  4. rootpath = "http://path.com/to/root/location/";   // be sure to change this to your URL
  5.  
  6. function getZipcode(str)
  7. {
  8.     var url=rootpath + "ziplookup.asp?zipcode=" + str
  9.     
  10.     xmlHttp=GetXmlHttpObject(stateChanged)
  11.     xmlHttp.open("GET", url , true)
  12.     xmlHttp.send(null)
  13. }
  14.  
  15. function stateChanged()
  16. {
  17.     if (xmlHttp.readyState==4 || xmlHttp.readyState=="complete")
  18.     {
  19.         document.getElementById("citystate").innerHTML=xmlHttp.responseText
  20.     }
  21. }
  22.  
  23. function GetXmlHttpObject(handler)
  24. {
  25.     var objXmlHttp=null
  26.  
  27.     if (navigator.userAgent.indexOf("Opera")>=0)
  28.     {
  29.         alert("Opera not supported...")
  30.         return;
  31.     }
  32.     if (navigator.userAgent.indexOf("MSIE")>=0)
  33.     {
  34.         var strName="Msxml2.XMLHTTP"
  35.         if (navigator.appVersion.indexOf("MSIE 5.5")>=0)
  36.         {
  37.             strName="Microsoft.XMLHTTP"
  38.         }
  39.         try
  40.         {
  41.             objXmlHttp=new ActiveXObject(strName)
  42.             objXmlHttp.onreadystatechange=handler
  43.             return objXmlHttp
  44.         }
  45.         catch(e)
  46.         {
  47.             alert("Error. Scripting for ActiveX might be disabled")
  48.             return
  49.         }
  50.     }
  51.     if (navigator.userAgent.indexOf("Mozilla")>=0)
  52.     {
  53.         objXmlHttp=new XMLHttpRequest()
  54.         objXmlHttp.onload=handler
  55.         objXmlHttp.onerror=handler
  56.         return objXmlHttp
  57.     }
  58. }

And the form (x)html:

  1. <form id="frmdefault">
  2.  
  3. <tr>
  4.                         <td class="txtright">Zipcode:</td>
  5.                         <td class="txtleft"><input name="zipcode" type="text" id="zipcode" size="6" maxlength="5" onkeyup="getZipcode(this.value)" value="<%=request.cookies("OD")("zipcode")%/>" /></td>
  6.                     </tr>
  7.                     <tr>
  8.                         <td class="txtright" valign="bottom">City / State:</td>
  9.                         <td class="txtleft">
  10.                             <div id="citystate"><span class="hilite">(Enter Zip Code First)</span></div>
  11.                             
  12.                             <div id="citystate2">
  13.                                 <input class="hilite" type="text" id="city" name="city" maxlength="50" size="15" value="<%= request.cookies("OD")("city") %/>" />
  14.                                 <input class="hilite" type="text" id="state" name="state" maxlength="2" size="3" value="<%= request.cookies("OD")("state") %/>" />
  15.                             </div>
  16.                         </td>
  17.                     </tr>
  18. </form>

Obviously, that would be a part of the larger table you are working with that has the name, address, and so on above it.

Notice the onkeyup command on the zipcode input box? When you release a key, it initiates the AJAX process. In our case, it calls ziplookup.asp and passes in «this.value» or, the entered zipcode.

so, what does ziplookup.asp do with it?

  1. < %
  2.  
  3. If Len(request("zipcode")) = 5 Then
  4.     
  5.  
  6.     strCN = "Provider=SQLOLEDB.1;UID=XXXXXXX;Password=XXXXXXX;Persist Security Info=False;Initial Catalog=XXXXXXXX;Data Source=sqlbox1"
  7.  
  8.     Set Conn = Server.CreateObject("ADODB.Connection")
  9.     Conn.open strCN
  10.  
  11.     dim rst,bool,myval,citylist, statelist
  12.  
  13.     citylist = ""
  14.     statelist = ""
  15.  
  16.     set rst=server.CreateObject("adodb.recordset")
  17.     
  18.         sSQL =    "SELECT distinct city FROM [ZipCodes] where zip = '"& request("zipcode") &"'"
  19.  
  20.         Set rst = Server.CreateObject("ADODB.Recordset")
  21.         rst.ActiveConnection = conn
  22.         rst.open sSQL
  23.         
  24.         if not rst.eof Then
  25.             citylist = citylist & "<option value="""">Select City"
  26.             citylist = citylist & "<option value="""">---------------</option>"
  27.  
  28.             While Not rst.eof
  29.                 citylist = citylist & "<option value="""& rst(0) &""">"& rst(0) &"</option>" & VbCrLf
  30.                 rst.movenext
  31.             Wend
  32.  
  33.             citylist = "<select onchange=""fillcity(this.value);"" name=""selcity"">"& VbCrLf & citylist &"</select>"& VbCrLf
  34.             response.write citylist
  35.  
  36.         Else
  37.             response.write "<span class='hilite'>No Record of this Zip</span>"
  38.         end If
  39.         
  40.  
  41.         sSQL =    "SELECT distinct state FROM [ZipCodes] where zip = '"& request("zipcode") &"'"
  42.  
  43.         Set rst = Server.CreateObject("ADODB.Recordset")
  44.         rst.ActiveConnection = conn
  45.         rst.open sSQL
  46.         
  47.         if not rst.eof Then
  48.             statelist = statelist & "<option value="""">Select State</option>"
  49.             statelist = statelist & "<option value="""">---------------</option>"
  50.             
  51.             While Not rst.eof
  52.                 statelist = statelist & "<option value="""& rst(0) &""">"& rst(0) &"</option>" & VbCrLf
  53.                 rst.movenext
  54.             Wend
  55.  
  56.             statelist = "<select onchange=""fillstate(this.value);"" name=""selstate"">"& VbCrLf & statelist &"</select>"& VbCrLf
  57.             response.write statelist
  58.  
  59.         Else
  60.             response.write ""    'no need to echo is out twice...
  61.         end If
  62.  
  63.         set rst = nothing
  64.         set conn = Nothing
  65.  
  66. Else
  67.     response.write "<span class='hilite'>Enter all 5 digits</span>"
  68. End if
  69.  
  70. %>

The first thing we do is to check if the entered value is 5 digits. there is no use putting extra server load on the DB for something that will never be useful. So, we wait until there's been 5 digits entered in the input box, then we run through our query.

Since there are more than 1 city with similar zip codes, and the possibility that a zipcode might NOT be in my table that i found on the net somewhere.... I have given the option to enter in free-form as well. Selecting the drop down will auto populate the input for city and state.

That's where our onchange functions come in handy.

Make sure you have your form id'ed correctly:

  1. <form id="frmdefault">
  2. </form>

else, the DOM scripting won't work.

  1. function fillstate(str) {
  2.     var theform = document.getElementById("frmdefault");
  3.     theform.state.value = str;
  4. }
  5.  
  6. function fillcity(str) {
  7.     var theform = document.getElementById("frmdefault");
  8.     theform.city.value = str;
  9. }

Also, old browsers don't support these techniques, so keep this in mind. I built this in an all IE6 environment, so i don't have to worry about browser differences.

The onkeyup will fail if JS is disabled, so its good to have a «graceful degradation» option a well, be it a button or other method to get the data back to the form-- even if it requires a page load.

Well, there you have it. A nice and easy classic ASP AJAX example.

Get coding =0

Source:
asp_ajax_skeymedia.zip

10 comments

Gravatar #1. ssandalow
2 years and 2 months ago

Good Stuff...
Sholom Sandalow

Gravatar #2. Kai
1 year and 9 months ago

Very impressive and works a treat. Personally I would remove line ** If Len(request(«zipcode»)) = 5 Then ... Else ... End If** and use LIKE in the SELECT statement, i.e.
SELECT distinct city FROM [ZipCodes] where zip like '»& request(«zipcode») &»%'»
This obviously creates more overheads but it's nice to have and see all values being updated on every keystroke. UK zipcodes are different though so it may not be useful in US.

Gravatar #3. yukiandrews
1 year and 5 months ago

beautiful and thank you
any idea how i can retain the values selected from these dropdowns on submit?
[when the user uses the browser's back button they have to start over . . .]

Gravatar #4. Brian Cummiskey
1 year and 5 months ago

yukiandrews:

The best thing to do would be to store a session variable for the zipcode on the following page.

formactionpage.asp:

  1. session("zipcode") = request.form("zipcode")

and in your form, pre-populate the value for the zip code:

  1. <input type="text" name="zipcode" id="zipcode" value="<%= session("zipcode") %>" />

And finally, in the footer somewhere, call the javascript to iniitate the query. Note, it's important that this JS happens AFTER the form field is populated from the session variable (thus, a window.onload call in the head section will most likely be problematic)

  1. <script type="text/javascript">
  2. function postload() {
  3.   getZipcode(document.getElementById("zipcode"))
  4. }
  5.  
  6. window.onload = postload;
  7.  

This is un-tested and off the seat of my pants, so there may be some errors and/or typos :)

Hope this gives you some guidance. Good luck :)

Gravatar #5. tonytee
1 year and 4 months ago

Thanks man, I am one of the ASP classic programmer (READ: dinosaur). Your post is vert useful to me. Keep up the good job!

Gravatar #6. ubigdummie
1 year and 3 months ago

Brian, would it be possible to receive the complete source for your example here? I learn best that way. Thanks!

Gravatar #7. Brian Cummiskey
1 year and 3 months ago

ubigdummie,

Unfortunately this was part of an intranet project at my last company where I am no longer employed. Thus, I don't have access to the source code.

However, I did some copy paste action and made a full page of the posted code. This is untested as I don't have ASP or MSSQL on my blog webserver.

I have added a link to the source in the orig post. Again, un-tested.

Gravatar #8. gabru
1 year and 1 month ago

nice thing ... i thought you might be interested in an Ajax Library for classic ASP (ajaxed). Check http://www.webdevbros.net/ajaxed/
there are still guys around hacking classic ASP ;)

Gravatar #9. Cesar
1 year ago

Very great work my friend. You're certainly right about one thing...barely any good documentation out there about Classic ASP and Ajax. Thumbs up to you!!

Gravatar #10. Brian Cummiskey
1 year ago

After reviewing this post again, I've noticed a critical flaw. The query is subject to SQL Injection. Please be sure you are running a RegEx or some data parsing on all your variables that are entered into a SQL query like this.

In this case for US-based 5-digit zipcodes, we should do something like this:

  1. <%
  2. Function digitsonly(teststr)
  3.   dim isValid
  4.   dim regEx
  5.   
  6.   isValid = True
  7.   set regEx = New RegExp
  8.   
  9.   regEx.IgnoreCase = false
  10.   
  11.   regEx.Pattern = "^[0-9]{5}$"
  12.   isValid = regEx.Test(teststr)
  13.   
  14.   digitsonly = isValid
  15.   
  16. End Function
  17.  
  18. zipcode = request("zipcode")
  19.  
  20. if len(zipcode) = 5 then
  21.   if digitsonly(zipcode) = false then
  22.     response.write "bad data"
  23.     response.end
  24.   else
  25.     'do the query and the rest of the above ASP back end functions.
  26. end if
  27. %>

Write a comment

If you want to add your comment on this post, simply fill out the next form:





* Required fields

You can use these XHTML tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <code> <em> <i> <strike> <strong>.

No trackbacks

To notify a mention on this post in your blog, enable automated notification (Options > Discussion in WordPress) or specify this trackback url: http://​skeymedia.com/​classic-asp-and-ajax-tutorial/​trackback/