Something about Farcry has bothered me for a while. It is difficult to link to content programatically, especially if you have a navigation node with multiple content items under it. For example, I have an application that I was writing which contained a calendar and a registration piece. Each was a separate dmInclude under the same dmNavigation node. So, how do I create a “Register Now” button from the calendar to the registration piece programmatically? Sure, I could hard-code the objectID but that just wasn’t cutting it for this. Sure, it would work, but would be easily broken. If the registration piece was ever deleted and re-created, there would be a new UUID for it and the user would not be able to recover the functionality without editing code or the database record. So, I came up with a better solution…
Usually, you either know where in line the content object stands (i.e. it’s the 2nd item under the dmNavigation node) or you know the name/label (i.e. it’s always called “Class Registration”). I created a custom widget for obtaining this content item. The basics of how this works is that when you use the contentObjectGet() method in tree.cfc you are given a structure containing information regarding that navigation node. Inside that structure is an array called aObjectIDs which contains all of the content items under that node. By using that knowledge, we can grab anything we want as long as we know what node to look in.
Below is a copy of the code and a link to download the file if you want. Before we get to that, let’s look at the useage a bit:
First, we need to import a tag library (I always prefix mine with cWidgets for “custom widgets”). Here’s how we’d make the call:
<cWidgets:contentObjectGet navid="#request.navid#" getByLabel="1" labelToGet="Class Registration" r_stObj="stObjToGet">
We must pass in the navid to look in (default is #request.navid#). We have 2 options. We can either get the item by the label or by the index in the array. This example is doing it by label. We pass getByLabel=”1″ and labelToGet=”Class Registration” telling the function to find the content object called “Class Registration”. Note, the label must be passed in exactly.
The other option is to get the content item by index. Here’s an example of that:
<cWidgets:contentObjectGet navid="#request.navid#" getByIndex="1" indexToGet="2" r_stObj="stObjToGet">
Here we pass getByIndex=”1″ telling the widget to get the content item by index and we pass indexToGet=”2″ telling it to grab the 2nd item under that navigation node.
Notice that both examples have r_stObj=”stObjToGet”. This is the variable name that will be available to the calling script. If it is not passed in it will default to stObj but depending on where this is called from, it might overwrite the current stObj structure which would be an undesirable effect.
As promised, here is the code and a link to download it. Happy Farcry’ing:
<cfparam name="attributes.navid" default="#request.navid#"> <cfparam name="attributes.arrayName" default="aObjectIDs"> <cfparam name="attributes.indexToGet" default="1"> <cfif NOT isNumeric(attributes.indexToGet)> <cfset attributes.indexToGet = 1> </cfif> <cfparam name="attributes.labelToGet" default=""> <cfparam name="attributes.getByIndex" default="0"> <cfif NOT isBoolean(attributes.getByIndex)> <cfset attributes.getByIndex = 0> </cfif> <cfparam name="attributes.getByLabel" default="0"> <cfif NOT isBoolean(attributes.getByLabel)> <cfset attributes.getByLabel = 0> </cfif> <cfparam name="attributes.r_stObj" default="stObj"> <!--- if both getByIndex and getByLabel were passed, use getByIndex ---> <cfif attributes.getByIndex AND attributes.getByLabel> <cfset attributes.getByLabel = 0> <cfset attributes.getByIndex = 1> </cfif> <cfif attributes.getByLabel AND NOT len(trim(attributes.labelToGet))> <cfoutput> <!-- contentObjectGet:Error --> <!-- getByLabel was passed but a labelToGet was not --> </cfoutput> <cfset attributes.getByLabel = 0> <cfset attributes.getByIndex = 0> </cfif> <!--- Tree Object ---> <cfset oTree = application.factory.oTree> <!--- Get this navid object ---> <cfset stObj = oTree.contentObjectGet(attributes.navid)> <!--- Get content ---> <cfif attributes.getByIndex> <cfset caller[attributes.r_stObj] = oTree.contentObjectGet(stObj[attributes.arrayName][attributes.indexToGet])> <cfelseif attributes.getByLabel> <cfset found = 0> <cfloop from="1" to="#ArrayLen(stObj[attributes.arrayName])#" step="1" index="i"> <cfset stTemp = oTree.contentObjectGet(stObj[attributes.arrayName][i])> <cfif stTemp.label eq attributes.labelToGet> <cfset caller[attributes.r_stObj] = stTemp> <cfset found = 1> </cfif> </cfloop> <cfif NOT found> <cfset caller[attributes.r_stObj] = StructNew()> <cfoutput> <!-- contentObjectGet:Error --> <!-- Label received "#attributes.labelToGet#". I was not able to find that label. --> </cfoutput> </cfif> <cfelse> <cfset caller[attributes.r_stObj] = StructNew()> <cfoutput> <!-- contentObjectGet:Error --> <!-- getByIndex or getByLabel must be passed. I did not receive either. --> </cfoutput> </cfif>