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 in anything from asp to cfm to php to ruby/rails to java and even old-school perl cgi’s.

First and foremost, AJAX is a very simple concept. Get it out of 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 an entered zipcode.
This is a simple database pull, but because the zipcode is like the 5th thing asked, and there’s 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.

  • an (x)HTML form or something along these lines
  • JavaSscript scripting to pass the http request and to receive the return response
  • and a server-side script or some other processor to ‘do the dirty work’ and return data back to the JavaScript that called it

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.


var xmlHttp;
var rootpath;

rootpath = "http://path.com/to/root/location/";   // be sure to change this to your URL

function getZipcode(str)
{
    var url = rootpath + "ziplookup.asp?zipcode=" + str;
   //we'll do a GET lookup here to keep things simple.  POST also works, but adds a bit extra to it that is not relevant for this example
    
    xmlHttp = GetXmlHttpObject(stateChanged);
    xmlHttp.open("GET", url , true);
    xmlHttp.send(null);
}

function stateChanged()
{
    if (xmlHttp.readyState==4 || xmlHttp.readyState=="complete")
    {
        document.getElementById("citystate").innerHTML=xmlHttp.responseText
    }
}

function GetXmlHttpObject(handler)
{
    var objXmlHttp=null;

    if (navigator.userAgent.indexOf("Opera")>=0)
    {
        alert("Opera not supported...");
        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;
    }
}

And the form (x)html:


<form id="frmdefault">

<tr>
                        <td class="txtright">Zipcode:</td>
                        <td class="txtleft"><input name="zipcode" type="text" id="zipcode" size="6" maxlength="5" onkeyup="getZipcode(this.value)" value="<%=request.cookies("OD")("zipcode")%/>" /></td>
                    </tr>
                    <tr>
                        <td class="txtright" valign="bottom">City / State:</td>
                        <td class="txtleft">
                            <div id="citystate"><span class="hilite">(Enter Zip Code First)</span></div>
                            
                            <div id="citystate2">
                                <input class="hilite" type="text" id="city" name="city" maxlength="50" size="15" value="<%= request.cookies("OD")("city") %/>" />
                                <input class="hilite" type="text" id="state" name="state" maxlength="2" size="3" value="<%= request.cookies("OD")("state") %/>" />
                            </div>
                        </td>
                    </tr>
</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?


< %

If Len(request("zipcode")) = 5 Then
    strCN = "Provider=SQLOLEDB.1;UID=XXXXXXX;Password=XXXXXXX;Persist Security Info=False;Initial Catalog=XXXXXXXX;Data Source=sqlbox1"
    Set Conn = Server.CreateObject("ADODB.Connection")
    Conn.open strCN

    dim rst,bool,myval,citylist, statelist

    citylist = ""
    statelist = ""

    set rst=server.CreateObject("adodb.recordset")
    
        sSQL =    "SELECT distinct city FROM [ZipCodes] where zip = '"& request("zipcode") &"'"

        Set rst = Server.CreateObject("ADODB.Recordset")
        rst.ActiveConnection = conn
        rst.open sSQL
        
        if not rst.eof Then
            citylist = citylist & "<option value="""">Select City</option>"
            citylist = citylist & "<option value="""">---------------</option>"

            While Not rst.eof
                citylist = citylist & "<option value="""& rst(0) &""">"& rst(0) &"</option>" & VbCrLf
                rst.movenext
            Wend

            citylist = "<select onchange=""fillcity(this.value);"" name=""selcity"">"& VbCrLf & citylist &"</select>"& VbCrLf
            response.write citylist

        Else
            response.write "<span class='hilite'>No Record of this Zip</span>"
        end If
        
        sSQL =    "SELECT distinct state FROM [ZipCodes] where zip = '"& request("zipcode") &"'"

        Set rst = Server.CreateObject("ADODB.Recordset")
        rst.ActiveConnection = conn
        rst.open sSQL
        
        if not rst.eof Then
            statelist = statelist & "<option value="""">Select State</option>"
            statelist = statelist & "<option value="""">---------------</option>"
            
            While Not rst.eof
                statelist = statelist & "<option value="""& rst(0) &""">"& rst(0) &"</option>" & VbCrLf
                rst.movenext
            Wend

            statelist = "<select onchange=""fillstate(this.value);"" name=""selstate"">"& VbCrLf & statelist &"</select>"& VbCrLf
            response.write statelist

        Else
            response.write ""    'no need to echo it out twice...
        end If

        set rst = nothing
        set conn = Nothing

Else
    response.write "<span class='hilite'>Enter all 5 digits</span>"
End if

%>

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:


<form id="frmdefault">
</form>

else, the DOM scripting won’t work.


function fillstate(str) {
    var theform = document.getElementById("frmdefault");
    theform.state.value = str;
}

function fillcity(str) {
    var theform = document.getElementById("frmdefault");
    theform.city.value = str;
}

Some 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. Editors Note: This article is several years old now and some concepts for browser testing likely has changed

The onkeyup event handler won’t do anything if JS is disabled by a user, so it’s a good idea 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

This entry was posted in Programming. Bookmark the permalink.

24 Responses to Classic ASP and AJAX

  1. ssandalow says:

    Good Stuff…
    Sholom Sandalow

  2. Kai says:

    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.

  3. yukiandrews says:

    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 . . .]

  4. yukiandrews:

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

    formactionpage.asp:

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

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


    <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)


    <script type="text/javascript">
    function postload() {
      getZipcode(document.getElementById("zipcode"))
    }

    window.onload = postload;

    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 :)

  5. tonytee says:

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

  6. ubigdummie says:

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

  7. 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.

  8. gabru says:

    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 ;)

  9. Cesar says:

    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!!

  10. 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:


    <%
    Function digitsonly(teststr)
      dim isValid
      dim regEx
      
      isValid = True
      set regEx = New RegExp
      
      regEx.IgnoreCase = false
      
      regEx.Pattern = "^[0-9]{5}$"
      isValid = regEx.Test(teststr)
      
      digitsonly = isValid
      
    End Function

    zipcode = request("zipcode")

    if len(zipcode) = 5 then
      if digitsonly(zipcode) = false then
        response.write "bad data"
        response.end
      else
        'do the query and the rest of the above ASP back end functions.
    end if
    %>

  11. AlmostBaldFromStress says:

    Man thanks,
    I have looked all over the web from some guidance and I guess I finally entered the right keywords cause here it is. I only have one question. How much do you have to change the database call if you are using mySql instead of SQL server?

  12. brian says:

    SQL Server and MySql are 98% similar in T-SQL structure.

    The major differences are TOP vs LIMIT (ie, select top 2 from table in MSSQL vs select * from table Limit 2 in MySql), multi-phrase column name ticking (ie, backticks vs [] brackets, and group by’s are not as strickt in mysql. Other than a few other advanced techniques (triggers, etc) the syntax is very similar.

    In this particular example, the only thing that would need to be changed would be to change [zipcode] to `zipcode` (note, those are back ticks, not quote marks). You can also leave the ticks off completely as it is a single string (ie, the field name is not `zip code` with a space).

  13. Mark says:

    We switched from ASP to AJAX last year and we’ve got lot of advantages: AJAX is quicker and more reliable than ASP.

  14. Brian says:

    Mark, I think you’re mis-using one of the technologies then. AJAX is NOT a replacement for ASP or ANY server-side language. It’s simply the call method instead of traditional GET/POST.

  15. Julie says:

    Thanks for this. Our entire website is vbScript/Javascript and I have no idea when it would change. This makes all sorts of things possible for us that weren’t an option using vbScript/Javascript/SQL alone.

  16. Hi. I wanted to drop you a quick note to impart my thanks. I’ve been observing your blog for a month or so and have picked up a heap of effective information as well as relished the way you’ve structured your site. I am attempting to run my own blog however I think its too general and I would like to focus more on smaller topics.

  17. David says:

    This is such a great treasure to find! I’m getting into AJAX late in the game and was having a real difficult time with understanding how to get ASP data and use it with javascript, like it was a clash of two worlds. The instructions made it very clear – thanks.

    One issue I found is that the closing tags for the ‘input’ ASP value tags have a stray closing slash between the ‘%’ and ‘>’, as in:
    value=”"

    This prevented the page from loading until corrected.

  18. brian says:

    This is for XHTML compliance. It shouldn’t have any bearing on ASP parsing correctly.


    <input type="button" />

    is 100% valid XHTML.


    <input type="button">

    is not.

  19. Al Willmott says:

    This is a great article! There are still legacy ASP apps out there which this works with amazingly well!! Thanks very much.

  20. Whitaker says:

    I appreciate any classic asp information. There are more of us out there than anyone gives credit. I am getting a `permission denied` error when I begin typing into the text field. I have the connection string worked out with my ID/PW (and it works on other pages for this table), but I cannot figure out where this may be coming from… Any ideas? Thanks!!!

    W-

  21. Whitaker says:

    Got the permission denied worked out by putting in the complete address rather than using the var url on line 17 of default.asp. But now it doesn’t do anything. It shows the form, but when text is input, nothing happens. Any ideas? Thanks!

  22. brian says:

    If you don’t have it, get the web developer tool bar for firefox. It is the number 1 tool for testing javascript, as you get an error box with a single click that usually points to the error.
    http://chrispederick.com/work/web-developer/

  23. Varun says:

    Cool …thanks…

  24. Del says:

    i run in dreamweaver cs5 this code but server error??
    this error:
    The server encountered an internal error and was unable to complete your request. Either the server is overloaded or there was an error in a CGI script.

    can you help me???

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>