I've finally gotten around to writing the follow up to my last entry on building a simple calendar in ColdFusion. I mentioned that the next entry was going to focus on making the CSS a bit more configurable, but that's boring. I'll do that next. What folks really want is an example of sending data to the custom tag. So let's get to it.
First off - lets talk about calendar data. Our custom tag is meant to be abstract, but as we all know, applications are not (typically) abstract. In fact, this was the main reason why I took so long to write these calendar write ups. (The first entry was actually written back in 2005.)
So I decided to just say screw it. My tag will make some basic assumptions if you want to use it and that's that. The assumptions are pretty simple though.
First off - your event data must be a query. Not a list. Not an array. Not a cow bell. But a query.
Secondly - your query must have a title, date, and link column. These columns will be what the custom tag will look for when displaying data.
So I don't think this is too bad. If your events data doesn't look exactly like this, you can always modify your query a bit to rename the columns. Plus, maybe I'll figure out a smart way to make this easier?
Let's jump into our custom tag. The first thing I'm going to do is add a new cfparam to create a default for our event data:
<cfparam name="attributes.events" default="">
I created a simple string for the events attribute. Later on I'll check to see if events is a query.
If you remember, we looped over each day of the month. Here was the original code:
<cfloop index="x" from="1" to="#days#"> <cfif x is day(attributes.today) and attributes.month is month(attributes.today) and attributes.year is year(attributes.today)> <cfoutput><td class="cell_today"></cfoutput> <cfelse> <cfoutput><td class="cell"></cfoutput> </cfif>
Now I'm going to add code that will check my query for events. I'll post the complete code, then I'll explain it:
<!--- check for stuff for today ---> <cfif isQuery(attributes.events)> <cfset thisDate = createDate(attributes.year, attributes.month, x)>
<cfquery name="todaysEvents" dbtype="query"> select title, link from attributes.events where [date] >= <cfqueryparam cfsqltype="cf_sql_date" value="#thisDate#"> and [date] < <cfqueryparam cfsqltype="cf_sql_date" value="#dateAdd("d", 1, thisDate)#"> </cfquery>
<cfif todaysEvents.recordCount> <cfoutput> <cfloop query="todaysEvents"> <cfif len(link)><a href="#link#"></cfif>#title#<cfif len(link)></a></cfif><br /> </cfloop> </cfoutput> </cfif> </cfif>
The first thing I do is check if attributes.event is actually a query. If it - I then create a date object for the current date.
Next I use query of query to look for events that occur within that date. Note how I add one to the date value to create the second boundary of my where clause.
Last - I check to see if my query of query returned anything. If it did, I simply output over the events.
Pretty simple, right? What's nice is that the custom tag will continue to work without event data if you want a simple calendar display. But now it supports passing in events and having them displayed (and linked as well).
Ok - so as I mentioned - your database probably won't match the structure the custom tag will use. What if there was a nice way around that? Turns out there is.
First I'm going to add 3 new attributes to my custom tag:
<cfparam name="attributes.datecolumn" default="date"> <cfparam name="attributes.titlecolumn" default="title"> <cfparam name="attributes.linkcolumn" default="link">
These all define defaults for the date, title, and link columns for my query. Now lets see how we can use this in the code:
<cfquery name="todaysEvents" dbtype="query"> select #attributes.titlecolumn# as title, #attributes.linkcolumn# as link from attributes.events where [#attributes.datecolumn#] >= <cfqueryparam cfsqltype="cf_sql_date" value="#thisDate#"> and [#attributes.datecolumn#] < <cfqueryparam cfsqltype="cf_sql_date" value="#dateAdd("d", 1, thisDate)#"> </cfquery>
This is the query we used before to determine if we had any events for today. However - now my column names are dynamic. I use aliases so I end up with the same column names. Now you can pass any query to the tag and simply tell it which columns to use for the title, link, and date columns.
I've attached the latest copy to this blog entry. In the follow up, I'll talk about how we can make the CSS a bit prettier. No, I haven't suddenly sprouted CSS genes. Instead I'll discuss how the custom tag can be told to rely on external CSS items instead. Enjoy.