Posted September 26, 2006 at
7:07 PM
Tags:
ColdFusion
I am posting this here to help someone on the House of Fusion CF-Talk mailing list. This demonstrates a really simple nesting custom tag example. In this demo, there are two custom tags: list.cfm and item.cfm. The item.cfm tags go in the list.cfm to create either a horizontal or vertical layout:
Launch code in new window » Download code as text file »
- <!--- Our parent list tag. --->
- <cf_list align="horizontal">
-
- <!--- A sub tag: item.cfm. --->
- <cf_item>
- Ashley Thomas
- </cf_item>
-
- <!--- A sub tag: item.cfm. --->
- <cf_item>
- Sarah Vivenzio
- </cf_item>
-
- </cf_list>
Before we get into the parent tag, let's explore the child tag first. Actually before we do that, let's just cover some nested tag basics:
- A tag can generate content if it has a close tag. That content is available in a variable THISTAG.GeneratedContent.
- The generated content of a tag is not available until the tag is running in execution mode: End. Think about it, if we are in the start tag, no content could possibly have been generated.
- Child tags associate themselves with parent tags.
- A parent tag DOES NOT know about its child (nested) tags until it is in its own End mode execution.
Ok, that being said, let's take a look at the child tag:
Launch code in new window » Download code as text file »
- <!--- Kill extra output. --->
- <cfsilent>
-
- <!---
- We only want to associate tag info with the parent in the
- first run of the sub tag. Otherwise, we might end up
- storing the info twice. Also, no need to validate
- attributes twice, the first time is sufficient.
- --->
- <cfif (THISTAG.ExecutionMode EQ "Start")>
-
- <!---
- Associate this tag with the parent tag. We are
- going to override the default value for data
- collection. It is usually AssocAttribs, which is a
- horrible name. We are going to store it in the
- structure "Items". This will allow the attribute data
- of the tag to be stored in parent tag.
-
- In this case, "list.cfm" is our parent tag. We define
- this association via the old school name "cf_list".
- --->
- <cfassociate
- basetag="cf_list"
- datacollection="Items"
- />
-
- <!--- Param tag attributes. --->
- <cfparam
- name="ATTRIBUTES.value"
- type="string"
- default=""
- />
-
- <!---
- Param the trim value flag. We are defaulting this
- to true. In that case, we will trim the value of
- the GENERATED CONTENT (not the Value attribute).
- --->
- <cfparam
- name="ATTRIBUTES.trimvalue"
- type="boolean"
- default="true"
- />
-
- </cfif>
-
- <!---
- Check to see if this tag as a closing tag. If it does,
- then we might be sending the value of the generated
- content instead of the value attribute.
- --->
- <cfif THISTAG.HasEndTag>
-
- <!---
- This tag might just be self closing (which would
- be considered a closing end tag. In that case, we
- won't have any length in our generated content
- (the content between the opening and closing tags.
- Check the length of the generated contet.
- --->
- <cfif Len( THISTAG.GeneratedContent )>
-
- <!---
- Since we have generated content, we are going
- to be using that as our list item value.
- Check to see if we need to trim this.
- --->
- <cfif ATTRIBUTES.trimvalue>
-
- <!---
- Trim value and save it into the attributes.
- We don't need to store into attributes, but
- we already have the value, so why not.
- --->
- <cfset ATTRIBUTES.value = THISTAG.GeneratedContent.Trim() />
-
- <!--- Erase the generated content. --->
- <cfset THISTAG.GeneratedContent = "" />
-
- </cfif>
-
- </cfif>
-
- </cfif>
-
- </cfsilent>
I am not going to comment too much here because the code sample itself is very well commented. The one thing I will touch upon is the CFAssociate tag. I am hard coding the parent tag "cf_list". This does NOT need to be hard coded. You can use the GetBaseTagList() method to make it more dynamic:
Launch code in new window » Download code as text file »
- <cfassociate
- basetag="#ListLast( GetBaseTagList() )#"
- datacollection="Items"
- />
I would NOT recommend this as you never really know where the parent tag name will show up in the base tag list. I am just noting this so you can let your imagination run wild.
Ok, now let's take a look at the parent tag:
Launch code in new window » Download code as text file »
- <!--- Kill extra output. --->
- <cfsilent>
-
- <!---
- Check to see if we are in the start mode of the tag. There
- is no need to param any attributes after the start mode.
- --->
- <cfif (THISTAG.ExecutionMode EQ "Start")>
-
- <!---
- Param the align attribute. This till determine if we
- show the list one after another in-line, or if the
- list should be displayed as block elements.
-
- Possible values:
- - horizontal (default)
- - vertical
- --->
- <cfparam
- name="ATTRIBUTES.align"
- type="string"
- default="horizontal"
- />
-
- </cfif>
-
- </cfsilent>
-
- <!---
- Since this is a parent tag that is designed to have child
- tags, we can't really do anything until the child tags have
- been defined. Therefore, we can only really work in the
- End mode of execution.
- --->
- <cfif (THISTAG.ExecutionMode EQ "End")>
-
- <!---
- ASSERT:
- At this point, we should have all the child tags
- associated with this parent tag. As per the child tags,
- all the attribute data should be in a structure:
- THISTAG.Items.
- --->
-
- <!---
- Now, we have to check to see how to display the items.
- Vertically or horizontally?
- --->
- <cfif (ATTRIBUTES.align EQ "vertical")>
-
- <!--- Display veritcally. --->
-
- <!---
- Loop over the Items array. Remember, this array
- contains the attributes of the child tags. Remember
- to use CFOutput tags as custom tags are NOT natural
- CFOutput blocks.
- --->
- <cfoutput>
-
- <cfloop
- index="intI"
- from="1"
- to="#ArrayLen( THISTAG.Items )#"
- step="1">
-
- <!--- Output value. --->
- <p>
- Item #intI#: #THISTAG.Items[ intI ].value#
- </p>
-
- </cfloop>
-
- </cfoutput>
-
- <cfelse>
-
- <!---
- We are going with the default, which is vertical.
- You might think the first CFIF clause should be the
- default statement since the default is probably the
- most often used. By making the default the ELSE
- clause, we don't really have to validate the types
- passed in. But that's not really here nor there.
- --->
-
- <!---
- Loop over the Items array. Remember, this array
- contains the attributes of the child tags. Remember
- to use CFOutput tags as custom tags are NOT natural
- CFOutput blocks.
- --->
- <cfoutput>
-
- <cfloop
- index="intI"
- from="1"
- to="#ArrayLen( THISTAG.Items )#"
- step="1">
-
- <!--- Output value. --->
- Item #intI#: #THISTAG.Items[ intI ].value#
-
- </cfloop>
-
- </cfoutput>
-
- </cfif>
-
- </cfif>
Again, the code above is fairly well commented, so I will just let you take it in and process it. I know that the code samples here are not great, I will try to wrap this thing up in a ZIP and put it in the ColdFusion code snippets.
Download Code Snippet ZIP File
Comments (4) |
Post Comment |
Ask Ben |
Permalink |
Other Searches |
Print Page
What Other People Are Searching For
[ local search ]
coldfusion custom tags
[ local search ]
nested custom tags
[ local search ]
associate child tags with parent tag in coldfusion
[ local search ]
nesting coldfusion custom tags
Well written easy to follow example. Good work!
Posted by Dan G. Switzer, II
on Sep 27, 2006
at 12:00 PM
Dan,
Thanks :) Just trying to help people learn. Yahoo for learning!
Posted by Ben Nadel
on Sep 27, 2006
at 12:30 PM
Great work, not only on this article!
Posted by Thomas
on Feb 13, 2007
at 9:01 AM
Thanks dude! Let me know if can help you with anything (demos, reviewing code, whatever).
Posted by Ben Nadel
on Feb 13, 2007
at 9:05 AM
Post Comment |
Ask Ben