Wednesday, January 19, 2011

Type Ahead Searches with jQuery

I was working on a mobile app and wanted to try a type ahead search to easy the user typing on a phone keyboard. I was able to make the ajax calls using jQuery to get the data, but I ran into some race conditions. As the user typed I made an ajax call but sometimes the first ajax call would take longer than the second. Thus updating the results with the first ajax calls data, because it finished later.

Example:
I starting typing "b". Then it would fire off an ajax call to get all the data with the letter "b".

Next I typed "a". So my search input box looked like this "ba". And firing off another ajax call to get all the data with the letters "ba".

I didn't know this but you can put the ajax request in a variable and kill it. Check it out.

<script type="text/javascript">
var ajaxCall;
typeAheadSearch = function(){
if(ajaxCall != undefined){
ajaxCall.abort();
}

ajaxCall = jQuery.ajax({
url: "http://www.somedomain.com/typeAheadSearch/_results.cfm",
data:{search:jQuery("##search").val()},
success:function(data){
jQuery("##results").html(data);
}
});
};
</script>

I started a variable called "ajaxCall" to store the request in. The first thing I do in the typeAheadSearch() is kill the current request by calling abort(). The next thing that I didn't know you could is that jQuery's ajax() returns the request. This is so handy.

Tuesday, January 4, 2011

CF9 computed properties

I wanted to make a computed property in CF9 just like you can on a sql table (computed column). Dan Vega had a nice how-to awhile back but it didn't show a complex example.

In my project I had a "project" class that had many ratings on it (Example: rating of 1-5, 1 being bad and 5 being great) and I wanted to have a computed property that gave me the average rating of a project. Here is what my hib file looks like for the "project" class.


<class entity-name="Project" lazy="true" name="cfc:myproject.app.model.Project" table="`Project`">
<id name="id" type="int">
<column length="10" name="ID" />
<generator class="identity" />
</id>
<property name="name" type="string">
<column name="Name" sql-type="varchar(max)" />
</property>
<property name="description" type="string">
<column name="Description" sql-type="varchar(max)" />
</property>
<property type="float"
formula="(select (sum(r.rank)*100.0) / (count(pr.id) *100.0) from project as p inner join project_rating as pr on pr.project_id = p.id inner join rating as r on r.id = pr.rating_id where pr.project_id = id)"
name="rating"/>
</class>

Some key things to point out:
1. The formula is a sql query not a hql query.
2. I wrapped my entire statement in (), don't know why but it worked.
3. You always start the sql statement with the table of the class you are working on. Reason being is when you get to the "where" clause notice this piece "pr.project_id = id". "id" is not aliased because it grabs the current id of the object that is running the formula against. This is how the query will only run for single object and not all of the other db records in the project table.
4. Alias every thing except the "where id" part.

I struggled through these above. Hope this helps someone.