<cffunction name="getObjectsParents" access="public" output="false" returntype="array">
<cfargument name="object" required="true"/>
<cfargument name="result" required="false" default="#[]#"/>
<cfif isObject(arguments.object.parent())>
<cfset arrayPrepend(arguments.result,arguments.object.parent())/>
<cfreturn getObjectsParents(arguments.object.parent(),arguments.result)/>
<cfelse>
<cfreturn arguments.result/>
</cfif>
</cffunction>
Monday, March 28, 2011
ColdMVC: get an object's parents
Awhile back I posted on flattening an array of objects with Parent-Child relationship (link) and have been using it alot. But one issue I had with it was when I was looping through the array of objects I didn't know who my parents were for the current object I was working with. I already knew how deep thanks to the treeDepth property. I made this function to recursively go up the tree of objects and bring back an array of parent objects for an object.
Thursday, February 3, 2011
ColdMVC: Number Tag
I've playing around with mobile web apps lately. ColdMVC has been a big help in getting them done quickly and "in the cloud".
I've been looking for a house since the market is so good right now and one thing I noticed when searching for houses online is the when you type in a price range only the keypad shows up on my phone. No letters. Just numbers. It's really nice. I viewed the source when I got back to my laptop and found out they were doing it with <input type="number" >. I decided to hack a ColdMVC tag together to hanlde this.
Here is how you call the tag...
Here is my hacked in logic...
The above logic doesn't supporting binding, but it works to use. It would be cool if this tag was managed my ColdMVC HTMLHelper.cfc then I would have to worry about the attributes.
I've been looking for a house since the market is so good right now and one thing I noticed when searching for houses online is the when you type in a price range only the keypad shows up on my phone. No letters. Just numbers. It's really nice. I viewed the source when I got back to my laptop and found out they were doing it with <input type="number" >. I decided to hack a ColdMVC tag together to hanlde this.
Here is how you call the tag...
<c:number name="miles" value="#service.miles()#">
Here is my hacked in logic...
<cfparam name="attributes.class" default="input"/>
<cfparam name="attributes.value" default=""/>
<cfif thisTag.executionMode eq "end">
<cfoutput>
<cfsavecontent variable="attributes.field">
<input type="number" name="#attributes.name#" title="#attributes.name#" value="#attributes.value#" class="#attributes.class#"/>
</cfsavecontent>
</cfoutput>
<cfset thisTag.generatedContent = coldmvc.form.field(argumentCollection=attributes) />
</cfif>
The above logic doesn't supporting binding, but it works to use. It would be cool if this tag was managed my ColdMVC HTMLHelper.cfc then I would have to worry about the attributes.
Wednesday, February 2, 2011
ColdMVC: Binding
I really like the binding option in the form tag of ColdMVC. It takes an object from the param scope, prefixes all the elements within it, with model's name (ex. user.first_name), and sets the value from the object. It's very handy. Here is an example of what it currently does:
If you wanted to bind the form to 2 or more objects it would be cool if you could use a bind tag and group a set of elements within a form.
Or even better on the tag itself. (I think this available already, but I am not sure).
<c:form controller="user" action="save" bind="user">
<c:hidden name="id"/>
<c:input name="first_name"/>
<c:input name="last_name"/>
<c:buttons>
<c:submit label="save"/>
</c:buttons>
</c:form>
If you wanted to bind the form to 2 or more objects it would be cool if you could use a bind tag and group a set of elements within a form.
<c:form controller="student" action="save">
<c:bind key="user">
<c:hidden name="id"/>
<c:input name="first_name"/>
<c:input name="last_name"/>
</c:bind>
<c:bind key="student">
<c:input name="student_number"/>
</c:bind>
<c:buttons>
<c:submit label="save"/>
</c:buttons>
</c:form>
Or even better on the tag itself. (I think this available already, but I am not sure).
<c:form controller="student" action="save">
<c:hidden name="id" bind="user"/>
<c:input name="first_name" bind="user"/>
<c:input name="last_name" bind="user"/>
<c:input name="student_number" bind="student"/>
<c:buttons>
<c:submit label="save"/>
</c:buttons>
</c:form>
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.
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.
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.
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.
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.
Thursday, December 30, 2010
DSL's or Domain Specific Languages
I saw this at Adobe MAX last year and I finally got a chance to try it out. DSL or Domain Specifically Languages are languages that only reside in a domain, in our case the web app we are developing. A good example of where DSLs are used is in gMail in the search box. If you haven't noticed it yet they are really handy, but they only work in gMail. Another good one is MS Outlook, they support crazy operators. Here is what one would look like:

I grabbed this one from gMail. The convention seems to use a keyword followed by a ":". In the case above it's "from:". I have only found DSLs helpfully for search boxes. If you are going to use DSLs you need to have legend so your users know what keys are available. You need to support it everywhere or tell the user where it is supported. If you are going to use them you should do whatever it takes in the keys and language to make it easier for the user. DSLs should be quick to use. Some advanced DSLs might look like this "from:(name:*joe)" or something like that or if operators are involved.
Once the user enters the DSLs you need to parse the string and do something with it. I create a query criteria snippet for sql or orm queries to allow the user to search across other things in the search box.
DSLs aren't really user friendly that's why I would recommend "search areas". Search areas are much easier to read, but less flexible. I posted on it early tonight here.
I grabbed this one from gMail. The convention seems to use a keyword followed by a ":". In the case above it's "from:". I have only found DSLs helpfully for search boxes. If you are going to use DSLs you need to have legend so your users know what keys are available. You need to support it everywhere or tell the user where it is supported. If you are going to use them you should do whatever it takes in the keys and language to make it easier for the user. DSLs should be quick to use. Some advanced DSLs might look like this "from:(name:*joe)" or something like that or if operators are involved.
Once the user enters the DSLs you need to parse the string and do something with it. I create a query criteria snippet for sql or orm queries to allow the user to search across other things in the search box.
DSLs aren't really user friendly that's why I would recommend "search areas". Search areas are much easier to read, but less flexible. I posted on it early tonight here.
Getting all the URL params in Javascript
I've been updating a lot of href's lately and found these functions to be very handy. They basically take all the pars in a string and put them in a JS object. There is other functions out there that get you 1 url param, but I wanted them all. Reason being, is I need to see if that param exists and do some more checks on it for business logic, then take all the pars and turn then into a querystring and add them back to href again.
getURL() actually serves two purposes. If a url isn't passed in get the current url. And it also cleans off all of params so all you get the base url.
getURLParameters = function(url){
var results = {};
if(url == ""){
var url = window.document.URL.toString();
}
if (url.indexOf("?") > 0){
var splitURL = url.split("?");
params = splitURL[1].split("&");
for (var i=0;ivar param = params[i].split("=");
if (param[1] != "")
results[param[0]] = unescape(param[1]);
else
results[param[0]] = "";
}
}
return results;
};
getURL = function(url){
if(url == ""){
var url = window.document.URL.toString();
}
if(url.indexOf("?") > 0){
var splitURL = url.split("?");
url = splitURL[0];
}
return url;
};
getURL() actually serves two purposes. If a url isn't passed in get the current url. And it also cleans off all of params so all you get the base url.
Subscribe to:
Posts (Atom)