LogoLogo
HomeAPIBlog
2.5.0
2.5.0
  • INTRODUCTION
    • Getting Started
      • Running Local Development servers
      • Beginner Tutorial: Hello World
      • Beginner Tutorial: Hello Database
      • Tutorial: CFWheels, AJAX, and You
    • Frameworks and CFWheels
    • Requirements
    • Manual Installation
    • Upgrading
    • Screencasts
  • Command Line Tools
    • CLI Commands
    • wheels - commands
    • wheels generate - commands
    • wheels dbmigrate - commands
    • wheels plugins - commands
  • Working with CFWheels
    • Conventions
    • Configuration and Defaults
    • Directory Structure
    • Switching Environments
    • Testing Your Application
    • Contributing to CFWheels
    • Documenting your Code
  • Handling Requests with Controllers
    • Request Handling
    • Rendering Content
    • Redirecting Users
    • Sending Files
    • Sending Email
    • Responding with Multiple Formats
    • Using the Flash
    • Using Filters
    • Verification
    • Event Handlers
    • Routing
    • URL Rewriting
      • Apache
      • IIS
      • Tomcat
      • Nginx
    • Obfuscating URLs
    • Caching
    • Nesting Controllers
    • CORS Requests
  • Displaying Views to Users
    • Pages
    • Partials
    • Linking Pages
    • Layouts
    • Form Helpers and Showing Errors
    • Displaying Links for Pagination
    • Date, Media, and Text Helpers
    • Creating Custom View Helpers
    • Localization
  • Database Interaction Through Models
    • Object Relational Mapping
    • Creating Records
    • Reading Records
    • Updating Records
    • Deleting Records
    • Column Statistics
    • Dynamic Finders
    • Getting Paginated Data
    • Associations
    • Nested Properties
    • Object Validation
    • Object Callbacks
    • Calculated Properties
    • Transactions
    • Dirty Records
    • Soft Delete
    • Automatic Time Stamps
    • Database Migrations
      • Migrations In Production
    • Using Multiple Data Sources
  • Plugins
    • Installing and Using Plugins
    • Developing Plugins
    • Publishing Plugins
  • External Links
    • Source Code
    • Issue Tracker
    • Sponsor Us
    • Community
Powered by GitBook
LogoLogo
On this page
  • Default Wildcard Linking
  • Linking to Routes
  • Linking to Resources
  • A Deep Dive into Linking and Routing
  • Namespaces
  • Nested Resources
  • Linking to a Delete Action
  • Extreme Example
  • Images and Other Embedded HTML in Link Texts
  • Adding Additional Attributes Like class, rel, and id
  • What If I Don't Have URL Rewriting Enabled?
  • Linking in a Subfolder Deployment of CFWheels
  • Use the linkTo() Function for Portability

Was this helpful?

Edit on GitHub
Export as PDF
  1. Displaying Views to Users

Linking Pages

CFWheels does some magic to help you link to other pages within your app. Read on to learn why you'll rarely use an <a> tag ever again.

PreviousPartialsNextLayouts

Last updated 1 year ago

Was this helpful?

CFWheels's built-in function does all of the heavy lifting involved with linking the different pages of your application together. You'll generally be using within your view code.

As you'll soon realize, the function accepts a whole bunch of arguments. We won't go over all of them here, so don't forget to have a look at the for the complete details.

Default Wildcard Linking

When installing CFWheels, if you open the file at config/routes.cfm, you'll see something like this:

config/routes.cfm
mapper()
    .wildcard()
    .root(to="wheels##wheels", method="get")
.end();

The call to allows a simple linking structure where we can use the helper to link to a combination of controller and action.

For example, if we had a widgets controller with a new action, we could link to it like this:

#linkTo(text="New Widget", controller="widgets", action="new")#

That would generally produce this HTML markup:

<a href="/widgets/new">New Widget</a>

Linking to Routes

If you're developing a non-trivial CFWheels application, you'll quickly grow out of the wildcard-based routing. You'll likely need to link to URLs containing primary keys, URL-friendly slugged titles, and nested subfolders. Now would be a good time to take a deep dive into the chapter and learn the concepts.

When you're using to create links to routes, you need to pay attention to 2 pieces of information: the route name and any parameters that the route requires.

Let's work with a set of sample routes to practice creating links:

config/routes.cfm
mapper()
    .get(name="newWidget", pattern="widgets/new", to="widgets##new")
    .get(name="widget", pattern="widgets/[key]", to="widgets##show")
    .get(name="widgets", to="widgets##index")
    .root(to="wheels##wheels")
.end();

With this in place, we can load the webroot of our application and click the "View Routes" link in the debugging footer to get a list of our routes. You'll see information presented similarly to this:

Name
Method
Pattern
Controller
Action

newWidget

GET

/widgets/new

widgets

new

widget

GET

/widgets/[key]

widgets

show

widgets

GET

/widgets

widgets

index

(As you become more experienced, you'll be able look at routes.cfm and understand what the names and parameters are. Of course, this View Routes functionality is a great tool too.)

If we want to link to the routes named newWidget and widgets, it's fairly simple:

#linkTo(text="All Widgets", route="widgets")#
#linkTo(text="New Widget", route="newWidget")#

As you can see, you create links by calling a method with the route name passed into the route argument. That will generate these links:

<a href="/widgets">All Widgets</a>
<a href="/widgets/new">New Widget</a>

The widget route requires an extra step because it has that [key] parameter in its pattern. You can pass that parameter into linkTo as a named argument:

#linkTo(text="The Fifth Widget", route="widget", key=5)#

That will produce this markup:

<a href="/widgets/5">The Fifth Widget</a>

If you have a route with multiple parameters, you must pass all of the placeholders as arguments:

Example
<!--- config/routes.cfm --->
<cfscript>
mapper()
    .get(
        name="widgetVariation",
        pattern="widgets/[widgetKey]/variations/[key].[format]",
        to="widgetVariations##show"
    )
.end();
</cfscript>

<!--- View file --->
<cfoutput>
#linkTo(
    text="A fine variation (PDF)",
    route="widgetVariation",
    widgetKey=5,
    key=20
    format="pdf"
)#
</cfoutput>

<!--- HTML generated --->
<a href="/widgets/5/variations/20.pdf">A fine variation (PDF)</a>

Linking to Resources

Resources are the encouraged routing pattern in CFWheels, and you will likely find yourself using this type of route most often.

Once you setup a resource in config/routes.cfm, the key is to inspect the routes generated and get a feel for the names and parameters that are expected.

Consider this sample posts resource:

config/routes.cfm
mapper()
    .resources("posts")
.end();
Name
Method
Pattern
Controller
Action

posts

GET

/posts

posts

index

newPost

GET

/posts/new

posts

new

editPost

GET

/posts/[key]/edit

posts

edit

post

GET

/posts/[key]

posts

show

If we wanted to link to the various pages within that resource, we may write something like this on the index:

views/posts/index.cfm
<nav class="global-nav">
    #linkTo(text="All Posts", route="posts")#
</nav>

<h1>Posts</h1>
<p>
    #linkTo(text="New Post", route="newPost")#
</p>

<ul>
    <cfloop query="posts">
        <li>
            #linkTo(text=posts.title, route="post", key=posts.id)#
            [#linkTo(text="Edit", route="editPost", key=posts.id)#]
        </li>
    </cfloop>
</ul>

The above code would generate markup like this:

<nav class="global-nav">
    <a href="/posts">All Posts</a>
</nav>

<h1>Posts</h1>
<p>
    <a href="/posts/new">New Post</a>
</p>

<ul>
    <li>
        <a href="/posts/1">Some Title</a>
        [<a href="/posts/1/edit">Edit</a>]
    </li>
</ul>

A Deep Dive into Linking and Routing

Namespaces

Namespaces will generally add the namespace name to the beginning of the route.

Consider this namespace:

mapper()
    .namespace("admin")
        .resources("roles")
    .end()
.end();

To link to the roles resource, you would prefix it with the namespace name:

#linkTo(name="List Roles", route="adminRoles")#

#linkTo(text=role.title, route="adminRole", key=role.key())#

However, new and edit routes add the action name to the beginning of the route name:

#linkTo(text="New Role", route="newAdminRole")#
#linkTo(text="Edit Role", route="editAdminRole", key=role.key())#

Nested Resources

You have the ability to nest a resource within a resource like so:

mapper()
    .resources(name="websites", nested=true)
        .resources("pages")
    .end()
.end();

To link to the pages resource, you add the parent resource's singular name first (e.g., the parent website is added, making the route name websitePage):

<!---
    Also notice that the parent route's primary key parameter is
    `websiteKey`:
--->
#linkTo(text="All Pages", route="websitePages", websiteKey=website.key())#

#linkTo(text="New Page", route="newWebsitePage", websiteKey=website.key())#

<!--- And the child resource's primary key parameter is `key`: --->
#linkTo(
    text="Show Page",
    route="websitePage",
    websiteKey=website.key(),
    key=page.key()
)#

#linkTo(
    text="Edit Page",
    route="editWebsitePage",
    websiteKey=website.key(),
    key=page.key()
)#

Linking to a Delete Action

CFWheels 2.0 introduced security improvements for actions that change data in your applications (i.e., creating, updating, and deleting database records). CFWheels protects these actions by requiring that they happen along with a form POST in the browser.

A common UI pattern is to have a link to delete a record, usually in an admin area. Unfortunately, links can only trigger GET requests, so we need to work around this.

To link to a delete request's required DELETE method, we need to code the link up as a simple form with submit button:

#buttonTo(
    text="Delete",
    route="category",
    key=category.key(),
    method="delete",
    inputClass="button-as-link"
)#

Then it is up to you to style the form and submit button to look like a link or button using CSS (using whatever classes that you prefer in your markup, of course).

By the way, this will work with any request method that you please: post, patch, and put as well as delete.

Extreme Example

#linkTo(
    text='<i class="rock-fist"></i> CFWheels Rocks!',
    route="cfwheelsRocks",
    key=55,
    params="rocks=yes&referral=cfwheels.org",
    anchor="rockin",
    host="www.example.co.uk",
    protocol="https",
    onlyPath=false,
    encode="attributes"
)#

Which would generate this HTML (or something like it):

<a href="https://www.example.co.uk/cfwheels/rocks/55?rocks=yes&amp;amp;referral=cfwheels.org#rockin"><i class="rock-fist"></i> CFWheels Rocks!</a>

Images and Other Embedded HTML in Link Texts

#linkTo(
    text=imageTag(source="authors.jpg"),
    route="blogAuthors",
    encode="attributes"
)#

You can also use your CFML engine's built-in string interpolation to embed other HTML into the link text in a fairly readable manner:

#linkTo(
    text='<i class="fa fa-user"></i> #EncodeForHtml(employees.fullName)#',
    route="employee",
    key=employees.id,
    encode="attributes"
)#

Security Notice

If you decide to opt out of encoding, be careful. Any dynamic data passed in to un-encoded values should be escaped manually using your CFML engine's EncodeForHtml() function.

Adding Additional Attributes Like class, rel, and id

#linkTo(text="Check Out", route="checkout", class="button")#

The same goes for any other argument that you pass, including but not limited to id, rel, onclick, etc.

What If I Don't Have URL Rewriting Enabled?

#linkTo(
    text="This link isn't as pretty, but it still works",
    route="product",
    key=product.key()
)#

CFWheels will still correctly build the link markup:

<a href="/index.cfm/products/3">This link isn't as pretty, but it still works</a>

Linking in a Subfolder Deployment of CFWheels

<a
    href="/foo/index.cfm?route=product&amp;key=3">
    This link isn't as pretty, but it still works
</a>

Use the linkTo() Function for Portability

An <a> tag is easy enough, isn't it? Why would we need to use a function to do this mundane task? It turns out that there are some advantages. Here's the deal.

CFWheels gives you a good amount of structure for your applications. With this, instead of thinking of URLs in the "old way," we think in terms of what route we're sending the user to.

What's more, CFWheels is smart enough to build URLs for you. And it'll do this for you based on your situation with URL rewriting. Are you using URL rewriting in your app? Great. CFWheels will build your URLs accordingly. Not fortunate enough to have URL rewriting capabilities in your development or production environments? That's fine too because CFWheels will handle that automatically. Are you using CFWheels in a subfolder on your site, thus eliminating your ability to use URL rewriting? CFWheels handles that for you too.

Oh, and another reason is that it's just plain cool too. ;)

We would see these linkable routes generated related to the posts. (See the chapter on for information about posting forms to the rest of the routes.)

The chapter lists your options for generating URLs that are available in your application. Following is an explanation of how to link to the various types of routes available.

The helper generates a form with submit button. As you can see from the example, you can style the submit button itself by prepending any arguments with input (e.g., inputClass).

If you need even more control, you can code up your own with whatever markup that you like. Just be sure to pass method="delete" to the call to startFormTag.

If we were to use all of the parameters for , our code may look something like this:

If you'd like to use an image as a link to another page, pass the output of to the text argument of and use the encode argument to instruct linkTo to only encode attributes:

Like many of the other CFWheels view helpers, any additional arguments that you pass to will be added to the generated <a> tag as attributes.

For example, if you'd like to add a class attribute value of button to your link, here's what the call to would look like:

CFWheels will handle linking to pages without URL rewriting for you automatically. Let's pretend that you still have CFWheels installed in your site root, but you do not have URL rewriting on. How you write your call will not change:

The same would be true if you had CFWheels installed in a subfolder, thus perhaps eliminating your ability to use (depending on what web server you have). The same code above may generate this HTML if you had CFWheels installed in a subfolder called foo:

If you see the pattern, this gives your application a good deal of portability. For example, you could later enable URL rewriting or move your application to a different subfolder. As long as you're using to build your links, you won't need to change anything extra to your code in order to accommodate this change.

Lastly, if you later install a that needs to modify link markup, that plugin's hook is the helper.

linkTo()
linkTo()
linkTo()
documentation
wildcard()
linkTo()
Routing
linkTo()
Form Helpers and Showing Errors
Routing
buttonTo()
startFormTag()
linkTo()
imageTag()
linkTo()
linkTo()
linkTo()
linkTo()
URL Rewriting
linkTo()
linkTo()
plugin
linkTo()