Henry
Henry

Reputation: 32905

Make use of custom tag to avoid CFM files mingled with lots of HTML markups?

Have you had any success with uses of custom tag for view that increase maintainability?

Does use of custom tag have any benefit of using basic <cfinclude>?

Any custom tag you have written before that increase HTML maintainability?

Thanks

Upvotes: 3

Views: 1229

Answers (2)

Dan Short
Dan Short

Reputation: 9616

Yes and Yes.

Custom tags are awesome for separating out reusable HTML elements. The advantages are that they are scope-safe, and you can pass arguments into them to change their behavior, which you can't do with cfinclude. You can even create nested tags that change their behavior based on their parents. Most of my HTML layouts in ColdFusion look something like this:

<cf_layout>
    <cf_head title="My Page>
    <!--- Some local head stuff ---->
    </cf_head>

    <cf_content>
        Lots of stuff goes here.
    </cf_content>
</cf_layout>

This is obviously greatly simplified, but I can change the entire layout of a site by changing the custom tag, or even changing the custom tag folder (think dynamic this.customTagPaths for swapping out layouts.

Custom Tags don't get enough love. Embrace them, and enjoy :).

Here's another example of something I do:

<cfset arOrders = OrderService.getOrders() />

<table>
    <cfloop array="#arOrders#" index="currentOrder">
        <cf_orderrow order="#currentOrder#" />
    </cfloop>
</table>

My OrderRow custom tag handles all of the display for displaying a row for an order in a table. This includes add/edit/delete buttons, calculations that have to happen, conditions that must be me to change the display. I can display an order row anywhere I want in an admin area. On the customer details page, on a page showing all orders in a certain time period. It makes no difference. My users know that any place they see a row describing an order, it will look just as they expect it to.

Here are a few more concrete examples of small custom tags I use across multiple applications.

cf_jquery

This includes jQuery and jQueryUI in a page, but only if no other template in the application has already added jQuery on this request. This allows me to build multiple jQuery parts to a page, and no matter what order I call them in, I'll always know that jQuery has been added to the head of the document only once.

<cfif thisTag.ExecutionMode EQ "end" AND (NOT StructKeyExists(Request, "JQueryInited") OR Request.JQueryInited EQ False)>
    <cfparam name="Attributes.IncludeUI" default="False" />
    <cfparam name="Request.jQueryUIInited" default="False" />
    <script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js"></script>
    <cfif Attributes.IncludeUI AND Request.jQueryUIInited IS False>
        <link href="/shared/css/smoothness/jquery-ui-1.8.11.custom.css" rel="stylesheet" />
        <script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jqueryui/1.8.11/jquery-ui.min.js"></script>
        <cfset Request.jQueryUIInited = True />
    </cfif>
    <cfset Request.JQueryInited = True />
</cfif>

I even build tags for small information that I know will be used throughout the application in multiple places, like this cf_contact tag:

<cfif thisTag.ExecutionMode EQ "end">
    <cfparam name="Attributes.Phone" default="xxx.xxx.xxxx" />
    <cfparam name="Attributes.Email" default="[email protected]" />
    <cfparam name="Attributes.EmailName" default="Email Support" />
    <h2 style="font: bold 12px Verdana, Geneva, Arial, Helvetica, sans-serif; margin-bottom: 0;">Contact Us</h2>
    <p style="text-align: left; margin-top: 0;"><cfoutput>#Attributes.Phone#</cfoutput><br />
    <cfoutput><a href="mailto:#Attributes.Email#">#Attributes.EmailName#</a></cfoutput></p>
</cfif>

Why make a tag for something so small? Why not? If I style all my contact information the same throughout an application (and I should, so users can easily identify things), then I can make a tag for it just as easily as I can make an include. If I decide I want some other programmatic behavior to happen in there, my app is already set up to use it.

cf_timeblock

This custom tag shows a set of select lists for choosing a time block (hh:mm tt). I use this all over an application dealing with scheduling, so I have a tag that will allow me to display a block for a time, and I can send in which values should be pre-selected (I'm missing validation for the attributes, but just pretend it's there for now):

<cfif thisTag.ExecutionMode EQ "end">
    <cfsilent>
        <!--- Get Time Blocks --->
        <cfset TimeBlocks = Application.DAO.getTimeQueries() />
    </cfsilent>
    <select name="hour" style="width: auto; float: none;">
        <cfoutput query="TimeBlocks.Hours">
            <option value="#TimeBlocks.Hours.Value#"<cfif TimeBlocks.Hours.Value EQ Attributes.Hour> selected="selected"</cfif>>
                #TimeBlocks.Hours.Value#
            </option>
        </cfoutput>
    </select>:<select name="min" style="width: auto; float: none;">
        <cfoutput query="TimeBlocks.Mins">
            <option value="#TimeBlocks.Mins.Value#"<cfif TimeBlocks.Mins.Value EQ Attributes.Min> selected="selected"</cfif>>
                #TimeBlocks.Mins.Value#
            </option>
        </cfoutput>
    </select>
    <select name="mer" style="width: auto; float: none;">
        <cfoutput query="TimeBlocks.Mer">
            <option value="#TimeBlocks.Mer.Value#"<cfif TimeBlocks.Mer.Value EQ FORM.mer> selected="selected"</cfif>>
                #TimeBlocks.Mer.Value#
            </option>
        </cfoutput>
    </select>
</cfif>

I use tons more than this, but they're all very application/object specific. Just about any time I start to pull something out into an include, or if I find myself copying a piece of display logic from one page to another, I start thinking about how I can push that code into a custom tag.

Here are a few more examples of custom tag libraries that I find useful.

Upvotes: 11

Adam Cameron
Adam Cameron

Reputation: 29870

One example missing from Dan's otherwise excellent efforts is the very powerful but under-utilised capabilities custom tags have to iterate over enclosed content:

<!--- loop.cfm --->
<cfif (THISTAG.ExecutionMode EQ "Start")>
    <cfparam name="attributes.index" type="variablename">
    <cfparam name="attributes.iterations" type="integer">

    <cfset variables.index = 1>
    <cfset caller[attributes.index] = variables.index>
<cfelse>
    <cfset variables.index = variables.index + 1>
    <cfif variables.index lte attributes.iterations>
        <cfset caller[attributes.index] = variables.index>
        <cfexit method="loop">
    <cfelse>
        <cfexit method="exittag">
    </cfif>
</cfif>

<!--- testLoop.cfm --->
<cf_loop iterations="10" index="i">
    <cfoutput>[#i#]</cfoutput>Hello World<br />
</cf_loop>

The one caveat I would offer for using custom tags is that I have heard they are prone to leaking memory (I cannot substaniate this), so if using them on a heavy-traffic site, I'd load test them thoroughly before going live with them.

Upvotes: 2

Related Questions