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.
When installing CFWheels, if you open the file at
config/routes.cfm, you'll see something like this:
For example, if we had a
widgetscontroller with a
newaction, 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>
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 Routing chapter and learn the concepts.
Let's work with a set of sample routes to practice creating links:
.get(name="newWidget", pattern="widgets/new", to="widgets##new")
.get(name="widget", pattern="widgets/[key]", to="widgets##show")
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:
(As you become more experienced, you'll be able look at
routes.cfmand 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
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
routeargument. That will generate these links:
<a href="/widgets">All Widgets</a>
<a href="/widgets/new">New Widget</a>
widgetroute requires an extra step because it has that
[key]parameter in its pattern. You can pass that parameter into
linkToas 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:
<!--- config/routes.cfm --->
<!--- View file --->
text="A fine variation (PDF)",
<!--- HTML generated --->
<a href="/widgets/5/variations/20.pdf">A fine variation (PDF)</a>
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
If we wanted to link to the various pages within that resource, we may write something like this on the index:
#linkTo(text="All Posts", route="posts")#
#linkTo(text="New Post", route="newPost")#
#linkTo(text=posts.title, route="post", key=posts.id)#
[#linkTo(text="Edit", route="editPost", key=posts.id)#]
The above code would generate markup like this:
<a href="/posts">All Posts</a>
<a href="/posts/new">New Post</a>
<a href="/posts/1">Some Title</a>
Namespaces will generally add the namespace name to the beginning of the route.
Consider this namespace:
To link to the
rolesresource, you would prefix it with the namespace name:
#linkTo(name="List Roles", route="adminRoles")#
#linkTo(text=role.title, route="adminRole", key=role.key())#
editroutes 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())#
You have the ability to nest a resource within a resource like so:
To link to the
pagesresource, you add the parent resource's singular name first (e.g., the parent
websiteis added, making the route name
Also notice that the parent route's primary key parameter is
#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`: --->
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
POSTin 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
GETrequests, so we need to work around this.
To link to a delete request's required
DELETEmethod, we need to code the link up as a simple form with submit button:
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:
putas well as
text='<i class="rock-fist"></i> CFWheels Rocks!',
Which would generate this HTML (or something like it):
<a href="https://www.example.co.uk/cfwheels/rocks/55?rocks=yes&amp;referral=cfwheels.org#rockin"><i class="rock-fist"></i> CFWheels Rocks!</a>
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:
text='<i class="fa fa-user"></i> #EncodeForHtml(employees.fullName)#',
#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.
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 linkTo() call will not change:
text="This link isn't as pretty, but it still works",
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>
This link isn't as pretty, but it still works
<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.
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 linkTo() to build your links, you won't need to change anything extra to your code in order to accommodate this change.
Oh, and another reason is that it's just plain cool too. ;)