Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
We have now seen how to set views to be rendered from our handlers. However, we can use some cool methods to render views and layouts on-demand. These methods exist in the Renderer and several facade methods exist in the super type so you can call it from any handler, interceptor, view or layout.
renderView()
renderExternalView()
renderLayout()
Check out the latest API Docs for the latest arguments:
Inline renderings are a great asset for reusing views and doing layout compositions
If you need rendering capabilities in your model layer, we suggest using the following injection DSL:
This will inject a provider of a Renderer into your model objects. Remember that renderers are transient objects so you cannot treat them as singletons. The provider is a proxy to the transient object, but you can use it just like the normal object:
You can pass localized arguments to the renderView() and renderLayout()
methods in order to encapsulate the rendering via the args
struct argument. Much like how you make method calls with arguments. Inside of your layouts and views you will receive the same args
struct reference as well.
This gives you great DRYness (yes that is a word) when building new and edit forms or views as you can pass distinct arguments to distinguish them and keep structure intact.
You can also pass in the caching arguments below and your view will be rendered once and then cached for further renderings. Every ColdBox application has two active cache regions: default and template
. All view and event caching renderings go into the template
cache.
So now that our views are cached, how do I purge them programmatically? Well, you need to talk to the template
cache provider and use the clearing methods:
Then we can perform several operations on views:
clearView(string viewSnippet)
: Used to clear a view from the cache by using a snippet matched according to name + cache suffix.
clearMultiView(any viewSnippets)
: Clear using a list or array of view snippets.
clearAllViews([boolean async=true])
: Can clear ALL cached views in one shot and can be run asynchronously.
To turn off view caching for your entire application, set the viewCaching
setting to false in your config/Coldbox.cfc
config file.
So what if I want to render a view outside of my application without using the setting explained above? Well, you use the renderExternalView()
method.
All rendered views have associated events that are announced whenever the view is rendered via ColdBox Interceptors. These are great ways for you to be able to intercept when views are rendered and transform them, append to them, or even remove content from them in a completely decoupled approach. The way to listen for events in ColdBox is to write Interceptors, which are essential simple CFC's that by convention have a method that is the same name as the event they would like to listen to. Each event has the capability to receive a structure of information wich you can alter, append or remove from. Once you write these Interceptors you can either register them in your Configuration File or programmatically.
Caution You can disable the view events on a per-rendering basis by passing the
prePostExempt
argument as true when callingrenderView()
methods.
Here is a sample interceptor that trims any content before it is renderer:
Of course, I am pretty sure you will be more creative than that!
Views are HTML content that can be rendered inside of a layout or by themselves. They can be either rendered on demand or by being set by an event handler. Views can also produce any type of content apart from HTML like JSON/XML/WDDX via our view renderer that we will discover also. So get ready for some rendering goodness!
Usually, event handlers are the objects in charge of setting views for rendering. However, ANY object that has access to the request context object can do this also. This is done by using the setView()
method in the request context object.
Setting a view does not mean that it gets rendered immediately. It means that it is deposited in the request context. The framework will later on in the execution process pick those variables up and do the actual rendering. To do immediate rendering you will use the inline rendering methods describe later on.
We use the setView()
method to set the view views/general/index.cfm
to be rendered. Now the cool thing about this, is that we can override the view to be rendered anytime during the flow of the request. So the last process to execute the setView()
method is the one that counts. Also notice a few things:
No .cfm
extension is needed.
You can traverse directories by using /
like normal cfinclude
notation.
The view can exist in the conventions directory views
or in your configured external locations
You did not specify a layout for the view, so the application's default layout (main.cfm
) will be used.
It is best practice that view locations should simulate the event. So if the event is general.index, there should be a general folder in the root views folder with a view called index.cfm.
Let's look at the view code:
I am using our cool HTML Helper class that is smart enough to render tables, data, HTML 5 elements etc and even bind to ColdFusion ORM entities.
So what happens if I DO NOT want the view to be rendered within a layout? Am I doomed? Of course not, just use the same method with the noLayout
argument or event.noLayout()
method:
If you need the view to be rendered in a specific layout, then use the layout
argument or the setLayout()
method:
If you need the set a view to be rendered from a specific ColdBox Module then use the module
argument alongside any other argument combination:
You can also tell the renderer to not render back anything to the user by using the event.noRender()
method. Maybe you just took some input and need to gracefully shutdown the request into the infamous white screen of death.
You can also omit the explicit event.setView()
if you want, ColdBox will then look for the view according to the executing event's syntax by convention. So if the incoming event is called general.index
and no view is explicitly defined in your handler, ColdBox will look for a view in the general
folder called index.cfm
. That is why we recommend trying to match event resolution to view resolution even if you use or not implicit views.
Tip: This feature is more for conventions purists than anything else. However, we do recommend as best practice to use explicitly declare the view to be rendered when working with team environments as everybody will know what happens.
Caution If using implicit views, please note that the name of the view will ALWAYS be in lower case. So please be aware of this limitation. I would suggest creating URL Mappings with explicit event declarations so case and location can be controlled. When using implicit views you will also loose fine rendering control.
You can also disable implicit views by using the coldbox.implicitViews
configuration setting in your config/ColdBox.cfc
. This is useful as implicit lookups are time-consuming.
The ColdBox rendering engine can also be tweaked to use case-insensitive or sensitive implicit views by using the coldbox.caseSensitiveImplicitViews
directive in your config/ColdBox.cfc
. The default is to turn all implicit views to lower case, so the value is always false.
ColdBox provides you with a very simple but flexible and powerful layout manager and content renderer. You no longer need to create module tags or convoluted broken up HTML anymore. You can concentrate on the big picture and create as many as your application needs. Then you can programmatically change rendering schemas (or skinning) and also create composite or component based views.
In this section we will explore the different rendering mechanisms that ColdBox offers and also how to utilize them. As you know, are our controller layer in ColdBox and we will explore how these objects can interact with the user in order to render content, whether HTML, JSON, XML or any type of rendering data.
Please note that you can use ColdBox as a pure API solution with modern JavaScript frameworks for the front end like VueJS, Reactor, Angular, etc.
Let's do a recap of our conventions for layouts and view locations:
The Renderer is a transient object in order to avoid variable collisions, meaning it is recreated on each request. All of the following property members exist in all layouts and views rendered by the Renderer:
As you can see, all views and layouts have direct reference to the request collections so it makes it incredibly easy to get and put data into it. Also, remember that the Renderer inherits from the Framework SuperType so all methods are at your disposal if needed.
This is a nifty little feature that enables you to create nice helper templates on a per-view, per-folder and per-application basis. If the framework detects the helper, it will inject it into the rendering view so you can use methods, properties or whatever. All you need to do is follow a set of conventions. Let's say we have a view in the following location:
Then we can create the following templates
homeHelper.cfm
: Helper for the home.cfm view.
generalHelper.cfm
: Helper for any view in the general folder.
homeHelper.cfm
That's it. Just append Helper to the view or folder name and there you go, the framework will use it as a helper for that view specifically. What can you put in these helper templates:
NO BUSINESS CODE
UI logic functions or properties
Helper functions or properties
Dynamic JavaScript or CSS
Hint External views can also use our helper conventions
You can also use the coldbox.viewsHelper
directive to tell the framework what helper file to use for ALL views and layouts rendered:
You have a few arguments in the renderView()
method that deal with collection rendering. Meaning you can pass any array or query and the Renderer will iterate over that collection and render out the view as many times as the records in the colleciton.
collection
: A data collection that can be a query or an array of objects, structs or whatever
collectionAs
: The name of the variable in the variables scope that will hold the collection pivot.
collectionStartRow
: Defaults to 1 or your offset row for the collection rendering
collectionMaxRows
: Defaults to show all rows or you can cap the rendering display
collectionDelim
: An optional delimiter to use to separate the collection renderings. By default it is empty.
Once you call renderView()
with a collection, the renderer will render the view once for each member in the collection. The views have access to the collection via arguments.collection or the member currently iterating. The name of the member being iterated as is by convention the same name as the view. So if we do this in any layout or simple view:
Then the tags/comment
will be rendered as many times as the collection rc.comments
has members on it and by convention the name of the variable is comment the same as the view name.
If you don't like that, then use the collectionAs argument:
So let's see the collection view now:
You can see that I just call methods on the member as if I was looping (which we are for you). But you will also see two little variables here:
_counter
: A variable created for you that tells you in which record we are currently looping on
_items
: A variable created for you that tells you how many records exist in the collection
This will then render that specific dynamic HTML view as many times as their are records in the rc.comments array and concatenate them all for you. In my case, I separate each iteration with a simple but you can get fancy and creative.
It is imperative to know who does the rendering in ColdBox and that is the Renderer class that you can see from our diagram above. As you can tell from the diagram, it includes your layouts and/or views into itself in order to render out content. So by this association and inheritance all layouts and views have some variables and methods at their disposal since they get absorbed into the object. You can visit the to learn about all the Renderer methods.
You can also use the ColdBox Renderer in your models so you can render email templates, views, etc. We won't inject the renderer directly because remember that the renderer is a transient object. So we will use a WireBox feature called , which will inject a proxy placeholder that looks like the renderer and behaves like the renderer. But behinds the scene it takes care of the persistence. So you can just use it!
Argument | Type | Required | Default | Description |
cache | boolean | false | false | Cache the view to be rendered |
cacheTimeout | numeric | false | (provider default) | The timeout in minutes or whatever the cache provider defines |
cacheLastAccessTimeout | numeric | false | (provider default) | The idle timeout in minutes or whatever the cache provider defines |
cacheSuffix | string | false | --- | Adds a suffix key to the cached key. Used for providing uniqueness to the cacheable entry |
Event | Data | Description |
preViewRender | view - The name of the view to render | Executed before a view is about to be rendered |
postViewRender | All of the data above plus: | Executed after a view was rendered |
Ok, now that we have started to get funky, let's keep going. How can I change the layout on the fly for a specific view? Very easily, using yet another new method from the event object, called setLayout()
or the layout
argument to the setView()
method.
This is great, so we can change the way views are rendered on the fly programmatically. We can switch the content to a PDF in an instant. So let's do that
If you need the set layout to be rendered from a specific module then use the module
argument from the setLayout() or renderLayout()
methods:
The default layout in a ColdBox application is layouts/main.cfm
by convention. You can change this by using the layoutSettings
in your Configuration.cfc
.
There is no default view in ColdBox, but you can configure one by using the same layoutSettings
configuration directive and the defaultView
directive:
This means that if no view is set in the request context, ColdBox will fallback to this view for rendering.
You can also wrap layouts within other layouts and get incredible reusability. This is accomplished by using the renderLayout()
method in the Renderer. As always, refer to the CFC API for the latest method arguments and capabilities.
So if I wanted to wrap my basic layout in a PDF wrapper layout (pdf.cfm
) I could do the following:
That's it! The renderLayout()
method is extremely power as it can allow you to not only nest layouts but actually render a-la-carte layout/view combinations also.
Property | Description |
| A reference to the Request Context object |
| A reference to the request collection inside of the request context (For convenience) |
| A reference to the private request collection inside of the request context (For convenience) |
|
|
| A reference to the application's ColdBox Controller (coldbox.system.web.Controller) |
|
|
|
|
A layout is simply an HTML file that acts as your shell where views can be rendered in and exists in the layouts
folder of your application. The layouts can be composed of multiple views and one main view. The main view is the view that gets set in the request collection during a request via event.setView()
usually in your handlers or interceptors.
You can have as many layouts as you need in your application and they are super easy to override or assign to different parts of your application. Imagine switching content from a normal HTML layout to a PDF or mobile layout with one line of code. How cool would that be? Well, it's that cool with ColdBox. Another big benefit of layouts, is that you can see the whole picture of the layout, not the usual cfmodule calls where tables are broken, or divs are left open as the module wraps itself around content. The layout is a complete html document and you basically describe where views will be rendered. Much easier to build and simpler to maintain.
Info Another important aspect of layouts is that they can also consume other layouts as well. So you can create nested layouts very easily via the
renderLayout()
method.
ColdBox provides you with a way to actually inject your layouts/views with custom UDF's, so they can act as helpers. This is called mixin methods and can be done via the includeUDF()
method in the supertype or via the following settings:
applicationHelper
- Global helper for layouts, views, and handlers
viewsHelper
- Global helper for all layouts and views only
Additionally, applicationHelper
can accept a list or array of helper files and will include each of them.
Caution If you try to inject a method that already exists, the call will fail and the CFML engine will throw an exception. Also, try not to abuse mixins, if you have too many consider refactoring into model objects or plugins.
ColdBox Elixir provides a clean, fluent API for defining basic tasks for your ColdBox applications. This project was forked from the project, so many many thanks for all their hard work and ideas. Please note that ColdBox does not ship with Elixir. It is an addon library based on Nodejs to help you with your asset pipeline.
Elixir supports several common CSS, JavaScript pre-processors, and TestBox runner integrations. By leveraging your familiar Gulpfile.js
configuration file, you can use method chaining and Elixir will allow you to fluently define your asset pipeline using the ColdBox conventions.
It works on the premise of two location convetions for your static assets:
includes
- Where your css/js will be placed after the pipeline executes
resources/assets
- Where all your resource files exist.
For example:
If you've ever been confused about how to get started with Gulp and asset compilation, you will love ColdBox Elixir. However, you are not required to use it while developing your application. You are free to use any asset pipeline tool you wish, or even none at all.
Tip : ColdBox Elixir supports EcmaScript6, JSX syntax, LESS, SASS, babel, browserify, vueify, partialify and much more. So take advantage!
Next, you'll want to pull in Gulp as a global NPM package so you have it available for any ColdBox application.
Once you have run this command, feel free to commit the npm-shrinkwrap.json
into source control.
It defines ColdBox Elixir, Bootstrap and jQuery as your dependencies. You may then install the dependencies it references by running:
This will install ColdBox Elixir, Bootstrap and jQuery into the node_modules
folder in your root. This folder has been already added to the .gitignore
file as well, so no need to further ignore it.
Note : If you are developing on a Windows system or you are running your VM on a Windows host system, you may need to run the
npm install
command with the--no-bin-links
switch enabled:npm install --no-bin-links
Elixir is built on top of Gulp, so to run your Elixir tasks you only need to run the gulp
command in your terminal, as you will already have a Gulpfile.js
in your project root that will resemble the following:
Please note that by adding the --production
flag to the command will instruct Elixir to minify your CSS and JavaScript files:
Since it is inconvenient to run the gulp command on your terminal after every change to your assets, you may use the gulp watch
command. This command will continue running in your terminal and watch your assets for any changes. When changes occur, new files will automatically be compiled or tested:
All rendered layouts have associated events that are announced whenever the layout is rendered via ColdBox Interceptors. These are great ways for you to be able to intercept when layouts are rendered and transform them, append to them, or even remove content from them in a completely decoupled approach. The way to listen for events in ColdBox is to write Interceptors, which are essential simple CFC's that by convention have a method that is the same name as the event they would like to listen to. Each event has the capability to receive a structure of information wich you can alter, append or remove from. Once you write these Interceptors you can either register them in your Configuration File or programmatically.
Caution You can disable the layout events on a per-rendering basis by passing the
prePostExempt
argument as true when callingrenderLayout()
methods.
Just like views, layouts can also have helpers on a per-layout, per-layout-folder or per-application basis. If the framework detects the helper, it will inject it into the rendering layout so you can use methods, properties or whatever. All you need to do is follow a set of conventions. Let's say we have a layout in the following location:
Then we can create the following templates
mainHelper.cfm
: Helper for the main.cfm
layout.
generalHelper.cfm
: Helper for any layout in the general
folder.
That's it. Just append Helper to the layout or folder name and there you go, the framework will use it as a helper for that layout specifically.
Caution Please note that layout helpers will be inheritenly available to any view rendered inside of the layout.
You can also use the coldbox.viewsHelper
directive to tell the framework what helper file to use for ALL layouts rendered:
A reference to the that can help you build interactive and safe HTML
A reference to the framework factory (coldbox.system.cache.CacheFactory)
A reference to the current configured Flash Object Implementation that inherits from the AbstractFlashScope (derived coldbox.system.web.flash.AbstractFlashScope)
The reference to the library (coldbox.system.logging.LogBox)
A pre-configured LogBox object for this specific class object (coldbox.system.logging.Logger)
A reference to the object factory (coldbox.system.ioc.Injector)
Before triggering Elixir, you must first ensure that is installed on your machine.
If you use a version control system, you may wish to run the npm to lock your NPM requirements:
The only remaining step is to install Elixir! If you generate a ColdBox application using any of our then you will find a package.json
file in the root of the application already. Think of this like your box.json
file, except it defines Node dependencies instead of ColdFusion (CFML) dependencies. A typical example can look like this:
Tip : If you are integrating with Vue.js, please see our section
ColdBox Elixir is fully documented here: . So please head on over there to get a deeper perspective of our asset pipeline manager.
Event | Data | Description |
| layout - The name of the layout to render | Executed before any layout is rendered |
| All of the data above plus: | Executed after a layout was rendered |
Now that we have seen what layouts and views are, where they are located and some samples, let's dig deeper. Let's discover the power of implicit layout/view declarations:
This layouts
setting allows you to implicitly define layout to view/folder assignments without the need of programmatically doing it. This is a time saver and a nice way to pre-define how certain views will be rendered. Let's see more examples:
In the sample, we declare the layout named popup
and points to the file Layout.Popup.cfm
. We can then assign it to views or folders:
Views
: The views to assign to this layout (no cfm extension)
Folders
: The folders and its children to assign to this layout. (regex ok)
This is cool, we can tell the framework that some views and some folders should be rendered within a specific layout. Wow, this opens the possibility of creating nested applications that need different rendering schemas!