Posted At : Dec 04, 2009 14:04 PM | Posted By : Ed Tabara
Related Categories: ColdFusion, AJAX, JavaScript

  • Given
  • Have a form with 3 fields: Zip (text field), City (text field), State (dropdown field).

  • Problem description
  • The user fills in the Zip. Then, when starting to fill the City, AutoComplete appear (from those that have filled Zip). When/If one is selected the State is filled automatically.

  • Solution
  • Nowadays there are many solutions for AJAX AutoComplete but i choosed the jQuery plugin from devbridge.com. It seem to work very well and on the site are given details on how to use it.
    So after incuding the library with
    <script type="text/javascript" src="js/jquery.autocomplete.js"></script>
    creating the form:
    <form name="frm" action="someactionhere" method="post">
    <strong>Zip:</strong> <input size="5" name="Zip" id="Zip" type="Text" value="#Zip#">
     <strong>City:</strong> <input size="30" name="City" id="City" type="Text" value="#City#">
     <strong>State:</strong> 
    <select name="State" id="State">
       <option value=""<cfif State eq ""> selected</cfif>>
       <cfloop query="getStates">
          <option value="#stateCode#"<cfif State eq stateCode> selected</cfif>> #stateName#
       </cfloop>
    </select>
    </form>

    and ading the JS:
    <script language="JavaScript" type="text/javascript">
       <!--
          var options, a;
          jQuery(function(){
             options =
                {
                   serviceUrl:'index.cfm?action=buyers.getCity&loadContent=true&Zip='+$('##Zip').val()
                   , maxHeight:150
                }
             a = $('##City').autocomplete(options);
          });
       //-->
    </script>

    i started to test it in order to move farther.

    And of course issues started. First problem was that the value from the Zip field was not passed to index.cfm?action=buyers.getCity. Instead of the value just entered was passed the one that was in the field at the start, so it wasn't exactly what i needed. Maybe there exist an easier way, i don't know, but after quite long playing with it i came to the following solution. I created a new JS function doAutoSuggest() and moved existing code into it and then made the call to it from City's onclick
    <form name="frm" action="someactionhere" method="post">
    <strong>Zip:</strong> <input size="5" name="Zip" id="Zip" type="Text" value="#Zip#">
     <strong>City:</strong> <input size="30" name="City" id="City" onclick="doAutoSuggest();" type="Text" value="#City#">
     <strong>State:</strong> 
    <select name="State" id="State">
       <option value=""<cfif State eq ""> selected</cfif>>
       <cfloop query="getStates">
          <option value="#stateCode#"<cfif State eq stateCode> selected</cfif>> #stateName#
       </cfloop>
    </select>
    </form>

    <script language="JavaScript" type="text/javascript">
       <!--
          function doAutoSuggest()
          {
             options =
                {
                   serviceUrl:'index.cfm?action=buyers.getCity&loadContent=true&Zip='+$('##Zip').val()
                   , maxHeight:150
                };
             $('##City').autocomplete(options);
          }
       //-->
    </script>

    The script that retrieves cities data and pass it back on the AJAX call is:
    <cfsetting showdebugoutput="No" enablecfoutputonly="Yes">
    <cfsilent>
       <cfparam name="query" default="">
       <cfparam name="Zip" default="">
       <cfquery name="getCities" datasource="#application.dsn#">
          Select distinct top 50 City + ', ' + st as ct, City + '|' + st as ct2
          From zips
          Where City like '#query#%'
             <cfif Len(Zip)>
                and zip = <cfqueryparam cfsqltype="CF_SQL_VARCHAR" value="#Zip#">
             </cfif>
          Order by ct asc
       </cfquery>
       <cfset items = QuotedValueList(getCities.ct, ",")>
       <cfset items2 = QuotedValueList(getCities.ct2, ",")>
    </cfsilent>
    <cfoutput>{ query:'#query#',suggestions:[#items#],data:[#items2#] }</cfoutput>

    Note that the Zip may not be entered and so there may be City with same name for different State. Because of it, in the suggestions i return city, state pairs and in data i place same pairs but without the blank after the comma so that it to can be used for later easy processing.
    What is left now is to make sure the City and State form fields are filled with the right values when something is selected in the AutoComplete dropdown.
    Because the data come in a city,state format we can split it and so onSelect to place it in needed form fields. But because the State is a dropdown element you can't just place the right value into it, you need to change the current selection. So, i created a JS function that taking as attribute the new value, will set it AND make the right selection.
    function getOptionInde<img src="images/smiles/14.gif" border="0">opt)
    {
       document.frm.State.value=opt;
       return document.getElementById('State').selectedIndex;
    }

    And so, the final code is as follow
    <form name="frm" action="someactionhere" method="post">
    <strong>Zip:</strong> <input size="5" name="Zip" id="Zip" type="Text" value="#Zip#">
     <strong>City:</strong> <input size="30" name="City" id="City" onclick="doAutoSuggest();" type="Text" value="#City#">
     <strong>State:</strong> 
    <select name="State" id="State">
       <option value=""<cfif State eq ""> selected</cfif>>
       <cfloop query="getStates">
          <option value="#stateCode#"<cfif State eq stateCode> selected</cfif>> #stateName#
       </cfloop>
    </select>
    </form>

    <script language="JavaScript" type="text/javascript">
       <!--
          function doAutoSuggest()
          {
             options =
                {
                   serviceUrl:'index.cfm?action=buyers.getCity&loadContent=true&Zip='+$('##Zip').val()
                   , maxHeight:150
                   , onSelect: function(value, data){ qwe=data.split("|");document.frm.City.value=qwe[0];document.frm.State.selectedIndex=getOptionInde<img src="images/smiles/14.gif" border="0">qwe[1]); }
                };
             $('##City').autocomplete(options);
          }

          function getOptionInde<img src="images/smiles/14.gif" border="0">opt)
          {
             document.frm.State.value=opt;
             return document.getElementById('State').selectedIndex;
          }
       //-->
    </script>

    Enjoy!

    Comments Comments (0) | Print Print | Email Send | 677 Views | 3% / 0% Popularity


    Posted At : Dec 09, 2008 19:59 PM | Posted By : Ed Tabara
    Related Categories: JavaScript

    We all time to time get visitors from Google Images and usually they just see our site in a frame, just copy the needed image and then forget about that site. Never wanted to have them REALLY land on your site? So they maybe finding something interesting there and becoming one of your repeated visitors?
    If so, there is a solution and it is dumb simple:

    Create refresh.js with the following code:
    if (window != top) top.location = self.location
    

    and put it say in the JS folder of your site. Then in the HEAD of your site place
    <script language="javascript" src="http://www.yoursite.com/js/refresh.js"></script>
    
    with the correct location to refresh.js.
    Done!

    Don't ask me if it in anyway break Google Policies or anything like that. I have NO IDEA about that, but i don't think it should. Plus, you can encode the JS anytime

    Comments Comments (2) | Print Print | Email Send | 1530 Views | 8% / 13% Popularity


    Posted At : Sep 26, 2008 0:44 AM | Posted By : Ed Tabara
    Related Categories: Other, JavaScript

    Ever wondered if your application could know when the client click BACK button in the browser so that the application to act accordingly? Well, it happen to be possible. After some googling and more tests and fails, here is what i came to.

    <script language="JavaScript" type="text/JavaScript">
    <!--
       window.onunload = backAlert();
       
       function backAlert()
       {
          window.onbeforeunload = function ()
          {
             if (true)
             {
                return "Warning! If you go back, your data will not be saved.";
             }
          }
          return false;
       }
    //-->
    </script>

    What it will do is to fire a confirmation alert when the back button will be hit. Actually it will fire that alert on some other events too, so for particular conditions you may want to alter the code.
    For example, if you have a form, the alert will appear on submit too. So, for this particular situation i would do the following:

    <form action="yourscript.cfm" method="post" name="frm" onsubmit="document.frm.tstfld.value=1;">
       <input name="tstfld" type="Hidden" value="0">
       <input type="Text" name="t1" value=""><br>
       <input type="Text" name="t2" value=""><br>
       <input type="Text" name="t3" value=""><br>
       <input type="Submit" value="Submit">
    </form>

    <script language="JavaScript" type="text/JavaScript">
    <!--
       window.onunload = backAlert();
       
       function backAlert()
       {
          window.onbeforeunload = function ()
          {
             if (document.frm.tstfld.value != 1)
             {
                if (true)
                {
                   return "Warning! If you go back, your data will not be saved.";
                }
             }
          }
          return false;
       }
    -->
    </script>

    So.... I have there a special hidden field with the value of zero that is changed to 1 when the form is submitted. And on the JS side make sure the alert will not happen when form submition happens.
    There should be an easier way to know when the form is submitted, but i could find it now.

    If anyone have better solutions, please share.

    Comments Comments (0) | Print Print | Email Send | 2704 Views | 14% / 0% Popularity