Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
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.
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 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.
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.
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.
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 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.
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!
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