Archive

Posts Tagged ‘component’

CFGrid Problem Solved!

August 14, 2009 1 comment

In my previous post My Adventure with CFGrid, I wrote about troubles I was having meeting some minor last minute client requirements.  In short, they want a cool table with Ajax features like paging, but they also want links in the table in an Actions column that are not Ajax and take the user to a detail page.  Sounds like an odd request for Ajax functionality but what the client wants the client gets.

My initial problem was how to add the links to the Actions column.  This was solved with the help of Ray Camden who suggested using the querySetCell() method to add my link data to the query recordset after the query is executed.  This worked well enough and my manager was impressed.  Something I didn’t pay attention to initially was that the pagesize attribute of cfgrid is ignored when the query attribute is specified.  The client definitely wants paging for larger recordsets, so the solution turned out to be using the bind parameter rather than the query attribute.

Having never used databinding before, I jumped right in and quickly found all sorts of little things that normally work, suddenly didn’t.  None of my APPLICATION or SESSION variables seemed to be available.  Variable not defined was what the error read.  By the way, I highly recommend Firebug for debugging Ajax requests.  The solution was to either hardcode my variables or add hidden form elements and then pass them in my bind parameter to the CFC.  I ended up using both to finally get my awesome looking cfgrid that pages through 10 records at a time and has an Actions column which takes the user to a detail page.

CFGrid goodness

While at CFUnited this I decided to ask around about why my SESSION and APPLICATION variables were coming up undefined when called via the bind parameter.  It was explained to me that bind is accessing the CFC directly rather than as a normal ColdFusion request and that is why they were not available.  This sounds reasonable to me, but I would like to get some confirmation.  So I pose the question to all my fellow CFers out there.  Is this really the case with databinding?

Advertisements

My Adventure With CFGrid

August 11, 2009 6 comments

I’m using a <cfgrid> to display some data returned from a query.  Not exactly rocket science, but I’ve managed to run into a bit of difficulty meeting a couple of final client requirements.  Let me set up the scene here.  First I have a form with several different search criteria, which are independent of each other.  Depending on which search criterion is selected, a different grid will display.  Each grid will has an Action column with links to another page.

First we call the CFC and add the “Actions” column to the returned query recordset:

<cfinvoke component=“#APPLICATION.ManageFieldOffice#” method=“retrieveProjectNames” returnvariable=“qRetrieveProjectNames” CountryID=“#CountryID#”/>

<cfset queryAddColumn(qRetrieveProjectNames, “viewlink”,“varchar”, arrayNew(1))/>

<cfloop query=“qRetrieveProjectNames”>

<cfsavecontent variable=“viewtext”>

<cfoutput>

<a href=“#APPLICATION.self##xfa.lnkViewFieldOffice#&cntFieldOffice=#cntFieldOffice#&vTab=1”>View</a> | <a href=“#APPLICATION.self##xfa.lnkViewCountry#&countryID=#CountryID#”>View Country Record</a>

</cfoutput>

</cfsavecontent>

<cfset querySetCell(qRetrieveProjectNames, “viewlink”,viewtext, currentRow)>

</cfloop>

Then we display the results in the grid:

<cfgrid format=“html” name=“countryResults” query=“qRetrieveProjectNames” pagesize=“25” width=“700” striperows=“true”>

<cfgridcolumn name=“cntFieldOffice” display=“false” headerbold=“true”>

<cfgridcolumn name=“strProjectName” header=“Project Name” width=“300” headerbold=“true”>

<cfgridcolumn name=“Country” headerbold=“true”>

<cfgridcolumn name=“strProjectNumber” header=“Project Code” headerbold=“true”>

<cfgridcolumn name=“viewlink” header=“” width=“200”>

</cfgrid>

Thanks to Ray Camden for his code example that guided me in creating the links for the Action column.

Here’s my CFC method:

<cffunction name=“retrieveProjectNames” output=“false” access=“public” returntype=“query” hint=“I retrieve all project office names”>

<cfargument name=“CountryID” type=“numeric” required=“false”/>

<cfargument name=“CountryList” type=“string” required=“false”/>

<!— var scope variables —>

<cfset var qRetrieveProjectNames = “”/>

<cftry>

<cfquery name=“qRetrieveProjectNames” datasource=“#variables.dsn#”>

SELECT tblFOAdminInfo.cntFieldOffice, tblFOAdminInfo.strProjectName, tblFOAdminInfo.strProjectNumber, tblFOAdminInfo.CountryID, tlkpCountry.Country

FROM tblFOAdminInfo

JOIN tblFOFieldOffices ON tblFOFieldOffices.cntFieldOffice = tblFOAdminInfo.cntFieldOffice

JOIN tlkpCountry ON tlkpCountry.CountryID = tblFOAdminInfo.CountryID

WHERE

tblFOFieldOffices.ysnDisable = <cfqueryparam value=“0” cfsqltype=“cf_sql_bit”>

<cfif IsDefined(“ARGUMENTS.CountryID”) AND ARGUMENTS.CountryID GT 0>

AND tblFOAdminInfo.CountryID = <cfqueryparam value=“#ARGUMENTS.CountryID#” cfsqltype=“cf_sql_integer”>

<cfelseif IsDefined(“ARGUMENTS.CountryList”)AND ARGUMENTS.CountryList NEQ “”>

AND tblFOAdminInfo.CountryID IN (#ARGUMENTS.CountryList#)

</cfif>

ORDER BY tblFOAdminInfo.strProjectName

</cfquery>

<cfreturn qRetrieveProjectNames />

<cfcatch type=“ANY”>

<cfreturn false>

</cfcatch>

</cftry>

</cffunction>

So here’s what the grid looks like:

cfgrid take 1So this works just fine, however there’s one small problem.  The client wants to page through large  recordsets.  Not an extraordinary request by any means, but I’ve run into a problem.  The <cfgrid> ignores the pagesize attribute when a query attribute is specified.  To get around this, I could just use a bind parameter in <cfgrid>, which I did.  This cuts down significantly on the code since I no longer need to cfinvoke my CFC method.  I call it right from the <cfgrid> tag.

My grid code now looks like this:

<cfgrid name=“regionResult2” format=“html” pagesize=“25” preservepageonsort=“true” width=“700” bind=“cfc:fieldoffice.field_v201_beta.cfapps.components.ManageCountry.getCountryByRegion({cfgridpage},{cfgridpagesize},{cfgridsortcolumn},{cfgridsortdirection}, getRegionSearchParam())”>

<cfgridcolumn name=“Country” header=“Countries” width=“550” headerbold=“true” />

<cfgridcolumn name=“viewlink” header=“Action” width=“200”>

</cfgrid>

I had to modify my CFC method as follows to supply the grid with the data:

<cffunction name=“getCountryByRegion” output=“false” access=“remote” returntype=“struct” hint=“I get Countries for a given strRegion”>

<cfargument name=“page” required=“true”/>

<cfargument name=“pagesize” required=“true”/>

<cfargument name=“gridsortcolumn” required=“true”/>

<cfargument name=“gridsortdirection” required=“true”/>

<cfargument name=“strRegion” type=“string” required=“true”/>

<cfset var qRetrieveCountryByRegion = “”/>

<cfquery name=“qRetrieveCountryByRegion” datasource=“FieldOffices”>

SELECT tlkpCountry.Country, tlkpCountry.CountryID

FROM tblFOCountry

INNER JOIN tlkpCountry ON tblFOCountry.CountryID = tlkpCountry.CountryID

WHERE tblFOCountry.strRegion = <cfqueryparam value=“#ARGUMENTS.strRegion#” cfsqltype=“cf_sql_varchar”>

ORDER BY tlkpCountry.Country

</cfquery>

<cfreturn queryconvertforgrid(qRetrieveCountryByRegion,page,pagesize) />

</cffunction>

A few things I learned in modifying my CFC method for this grid:

  1. I had to change the returntype from query to structure as Firebug showed a returntype is not of type query.
  2. Had to hardcode my DSN.  When I checked Firebug, I noticed the response was “Datasource ” not found” so my dynamic value was not working for some reason.
  3. Had to add the 4 standard cfgrid arguments

Since I eliminated my cfinvoke to call the method, I figured I’d just move my code to add the Actions link to the query recordset.  After the query is executed, I add the code and the use queryconvertforgrid() to return the whole thing.  Now my grid appears and paging is available, but there is no Actions column.

cfgrid take 2

I have to be missing something.  I cannot believe that I can’t add a link to a grid created using the bind parameter of the <cfgrid> tag.  Good thing I’m heading to CFUnited tomorrow.  Perhaps I can find some help there.

My life as a CF developer

June 20, 2008 Leave a comment

I am currently employed as web application developer at the Academy for Educational Develoment(AED) in Washington, DC.  AED uses Fusebox 4.1 for its ColdFusion development.  I was familiar with Fusebox, having toyed with it a few years ago back in Fusebox 3, so I wasn’t coming in totally cold, but pretty close.  During my first week, I did a lot of reading due to the fact that my laptop had not arrived; I was hired right after the holidays and things moved much faster than their normal hiring process with the exception of the equipment.

Now that I’ve had 6 months to get used to it and use it at least two different ways, I can confidently say that I like this framework.  We do not use Fusebox in an OO fashion as is becoming a trend these days.  Rather we are still procedural for the most part, but we do use CFCs for most of the newer applications.  I really like using CFCs in my code because it centralizes my queries and business logic.  What I have noticed, however, is that even among the three of us, we have different styles in our use of CFCs, particularly in how we call them.  One likes to use the old fashioned:

<cfset someVariable = path.to.component.method(arguments) />

This is perfectly acceptable and demonstrates a saying I often use in application development.  “There’s always another way to achieve the same task.”  The problem I have with accessing my components in this manner is that it doesn’t explicitly name the arguments as they are in the CFC.  In fact they could actually be different.  Additionally, it seems you have to pay close attention to the order of your arguments as you pass them to the component.  I inherited an application from my coworker and had to add a new argument, but didn’t pay attention to the order in which they were passed.  This resulted in an error in the function that wasn’t obvious at first.  Only after a little troubleshooting did we figure it out.  For this reason, my preferred method of calling my components is:

<cfinvoke component=”#componentName#” method=”methodName” returnvariable=”returnvariableName” argument1=”#argumentName#” argument2=”#argument2#”/>

Perhaps this is a holdover from my hatred of math.  I am very methodical and was never the kid who could skip steps when solving a math problem.  I had to work out each step in order to arrive at the solution.  Using the above method allows me to clearly and precisely state the component and method I am calling, as well as declare each argument I am passing in and naming the variable I will use to refer to the results of that method after execution.  It helps me when writing the act_ or dsp_ file using the data from whatever method to know this information up front.

I mentioned that we do not use CFCs in an object oriented fashion.  We tend to group our CFCs by circuits, usually with once CFC per circuit.  Additionally, it likely we’ll have one Lookup CFC to handle frequently used methods such as querying a lookup table for US States, or Regions, or Countries, or Months, etc.  In this way we can have those methods execute once and be available for whatever page might need them.

Using CFCs in this manner probably is not a best practice.  In fact, probably just the opposite, but it does work for us.  It does, however make for some very long CFCs.  I have a 500 line CFC in my current project.  Thank goodness for the CFC explorer in Eclipse, which makes it ever so easy to jump to a specific method. I have just recently learned about the CF Frameworks explorer in CFEclipse, which I’m finding extremely useful to not only explore the application from a single, outline-style list, but also as a means to help in writing my fuseactions for my circuit files in a slightly more organized way.