[coldbox 3.8.1] More Nested Layout questions

Going to start with a small complaint: The “nested layouts” documentation deals with . Would like to see something much simpler and encompassing more examples, certainly focusing on views.

I have a “primary” layout. Right now, it’s the layout for all the pages I will have. So just the one. I’m using a very expansive Twitter Bootstrap theme. I’ve already done the work of splitting out that main layout from the rest of the page types. However, there are several page types! Some are galleries, some are two column contents, some are image sliders. I may use two galleries, a three column page, and two sliders. Those “page types” have very little in the way of “real content” and much of the code is all css-related things like clearfix divs, etc. I would like the views to focus on the content.

So considering nested layouts, it would seem I would want to structure my layouts folder like this:

/layouts/primary.cfm

/layouts/pagetypes/gallery.cfm

/layouts/pagetypes/twoColumn.cfm

/layouts/pagetypes/threeColumn.cfm

/layouts/pagetypes/slider.cfm

Each of those files should likely have a #renderView()# in it. In my handler event code, I would expect I could say something like “setView(view=’/news/superTwoColumnPage’, layout=‘primary’, sublayout=‘pageTypes/twoColumn’)”. Clearly this is not the case. There’s no such thing.

It seems, if I can puzzle out the documentation on this feature, that I have do some sort of news HTML followed by renderLayout(layout=‘pageTypes/twoColumn’) ?

It just isn’t clear. How would the saved content get drawn. It has before and after code…so doing renderLayout(the sub layout) from the view can’t be right. Am I supposed to create my own prc variable that the layout looks for? Could someone give me a really clear explanation of what the layout files should look like (if different from normal), what the view code should be and how to get the sublayout to apply, too?

Or am I way off base and this just isn’t how it’s used? Do I have to create separate “real” layouts for every sub-layout type I might want to use? That can’t be right.

you can use renderView() to save to a variable and put that in the rc.

Sorry, Aaron, that answer isn’t as thorough of a response I was hoping for from the group. By putting a value in the RC, assuming a consistent variable name, that means I could only have one? Guess I had really thought there was more to it than this.

you can renderView() all the views you want. put them all in the rc. then display them in your layout.

Why not use viewlets?

In other words you have small views (viewlets) and a layout view that can tie all this together. For example

doHandlerEntryPoint(event) {

renderView(“viewletLayoutMain”);

}

Then in that view, you could easily do this as many times as you like.

#runEvent(“widget/Calendar”)#

#runEvent(“widget/Top 10 List”)#

The best part of using viewlets like this, you can encapsulate all the code into those events.

I pinged Luis to see if he has a better answer, but at this point I think your looking for something far more advanced to be built into the framework and it simply isn’t. We have some Django-style layout inheritance on our roadmap for ColdBox 4, but in the mean time you can still do what you want-- there’s just no established pattern you have to use.

A ColdBox event is currently allowed to specify a single layout and a single view to be rendered. The layout will be generated and wherever the renderView() with no args call is-- that is where the view will be put.

Now, that being said, you can render any additional view or layout from inside of any other view or layout, so the sky is basically the limit. You can even run events from inside a view or layout, which can, in turn, output HTML. You can set HTML into rc variables for output in the view/layout. You can even set rc flags of your design in your handler if you wish to control what sub layouts or views get included.

Really, anything goes. It’s up to you to decide how you wish to organize your site, how much control you need, and what mechanisms you want to employ to dynamically stitch together the pieces as long as it fits inside of the 1 main layout and 1 main view that you specify to ColdBox.

Thanks!

~Brad

ColdBox Platform Evangelist
Ortus Solutions, Corp

E-mail: brad@coldbox.org
ColdBox Platform: http://www.coldbox.org
Blog: http://www.codersrevolution.com

+1 to the approach Andrew described. It’s one of my favorites since the data needed for the viewlets can be self-contained in the event that is run. Just remember not to use event.setView() for your viewlets-- instead return the results of renderView() straight from the handler. The HTML will be the result output from the runEvent() call.

Thanks!

~Brad

ColdBox Platform Evangelist
Ortus Solutions, Corp

E-mail: brad@coldbox.org
ColdBox Platform: http://www.coldbox.org
Blog: http://www.codersrevolution.com

Brad, I think you really hit the nail on the head, in that what I was “thinking nested layouts” is, well, it isn’t that advanced.

What I’m trying to accomplish, I guess, would be the equivalent of taking my sublayout and breaking it into sublayout_top.cfm and sublayout_bottom.cfm, and then in my specific view, say

my real view content

Then all of that is simply treated as the entire view that then gets put into the true layout file as we are all used to.

The easy way (from the developer point of view) would be to allow something like setView/renderView(view=‘myview’, layout=‘myMainLayout’, sublayout=‘mySubLayout’).

Clearly that’s not as simple for the Coldbox team. I’ll just find another way for now.

Thanks for trying to help, guys! :slight_smile:

I agree and the more I use viewlets, the more I wonder why I don’t move/flip everything to that paradigm?

Well, I’m definitely using viewlets, but they are called from the layout (toolbars, footers, social media icons, etc.). But I’m talking about the main view, at least for what I was inquiring about.

In case anyone is interested, this conversation prompted me to put in a ticket to make calling viewlets a bit easier in so far as sticking to the default ColdBox conventions and not needing to program your viewlet events any different.

https://ortussolutions.atlassian.net/browse/COLDBOX-304

Feel free to give feedback on if this would be useful.

Thanks!

~Brad

ColdBox Platform Evangelist
Ortus Solutions, Corp

E-mail: brad@coldbox.org
ColdBox Platform: http://www.coldbox.org
Blog: http://www.codersrevolution.com

That’s an interesting feature request. I kind of like it. Except for one thing. I treat views and viewlets different. This is what I tell the coders: “A primary event should always do setView(). A renderView() may optionally call a handler function via runEvent().” I make this distinguishing factor so that none of my handler events have any “return renderView()” code. So that all handler functions can be output=false and returntype=void. If a viewlet does call a handler function, then the variables it needs should be in rc/prc when control is returned back to the viewlet.

Just one man’s opinion. I still like the idea, though, of the outputEvent(), because it accomplishes much the same thing if you know you absolutely should call a handler function to render said viewlet.

So this is what you do?

<cfset runEvent( ‘something.getData’ )>

#renderView( ‘viewName’ )#

I don’t typically do that and here’s why. The problem is encapsulation. Once you start doing a lot of this, or you have a dynamic layout where any number of viewlets can be included, your rc and prc scopes start bloating up with all sorts of variables-- kind of like a legacy CFML app where you just throw everything in the request or variables scope. Then you start having collisions on the page where multiple viewlets are all using the same variable names. In some cases, I need to include the same viewlet multiple times such as multiple file uploads on a single page.

For this reason, I render the view inside the handler AND couple that with the very handler view arguments feature that allows my handler to pass its data directly to the view and keep it out of the global rc and prc.

local.data = getData();
renderView( view=‘viewName’, args=local.data );

Of course, what’s nice is runEvent() also allows ad-hoc arguments to be passed directly into it via eventArguments (don’t ask me why the naming convention is different) which really lets you encapsulate your viewlets in the layout/view by repurposing a generic one and passing in context variables that don’t need to clutter rc and prc.

Thanks!

~Brad

ColdBox Platform Evangelist
Ortus Solutions, Corp

E-mail: brad@coldbox.org
ColdBox Platform: http://www.coldbox.org
Blog: http://www.codersrevolution.com

Brad,

I was about to reply with another approach, but stopped short to read your ticket first. Interceptors would work here as well, it might not be the overall solution, but it should work.

The best approach probably would be the invalidEvent() interception point, what you could do is check that the event being called has a view. Now if the view is outside of the convention expected this should work, but you could just do a simple filexists if it exists just return that appended to the buffer.

Or one could write their own helper. that provides that feature and cfincludes the view and appends it to the buffer.

Of course the last time I tried to read the buffer like this, the buffer was always empty. I asked about this 2-3 years ago why but never got an answer and found another solution to the problem. In this case getting the buffer is not an issue as you would just append to it, as the buffer is built up with each view rendering this should work like a charm as well.

Not the ideal overall solution, but it should work just the same.

The way that I have always approached this is the same, except one thing.

I actually create an API sort of approach that is used just for viewlets, which has a security interceptor attached to make sure these Events can only ever be called internally. It is not what I would call an ideal situation, but it has worked for me over the years.