Viewlet Overrides Layout

Could someone help me with viewlets? I was trying to implement a viewlet on my ColdBox-based app. Basically, I followed the steps explained on http://wiki.coldbox.org/wiki/Layouts-Views.cfm#Viewlets_(Portable_Events). When I ran it, the existing layout that calls the viewlet was not displayed. Instead, it got replaced by the viewlet.

Enviroment:

  • Windows 7 Professional

  • Railo 4.2.1

  • ColdBox 3.8.1

Code:
/handlers/viewlets.cfc

`
component {
function home(event, rc, prc) {
event.setView(“viewlets/home”);
}

function userinfo(event, rc, prc) {
prc.data.username = “jsmith”;
return renderView(“viewlets/userinfo”);
}
}
`

/views/viewlets/home.cfm
<cfoutput>#runEvent("viewlets.userinfo")#</cfoutput>

/views/viewlets/userinfo.cfm

`

Username: #prc.data.username#
`

/layouts/main.cfm

`

I am Layout.
#renderView()#
`

The way I called: http://test/index.cfm?event=viewlets.home and it redirected to http://test/index.cfm?event=viewlets.userinfo. Is this behavior correct? And, how to make the viewlet displayed inside the existing layout? Thank you.

Viewlets CAN NOT be called on other event handlers like this, because it will use that view instead.

If you want to provide logic to a viewlet you will need to use a handler that doesn’t override the view itself, in other words you’re doing it wrong!!

I am lost. Here’s another attempt from what I understand based on http://wiki.coldbox.org/wiki/Layouts-Views.cfm#Viewlets_(Portable_Events).

/handlers/main.cfc
component { function index(event, rc, prc) { prc.message = "Welcome!"; } }

/handlers/viewlets.cfc

component { function userinfo(event, rc, prc) { prc.username = "jsmith"; return renderView(view="viewlets/userinfo"); } }

/views/main/index.cfm

I am main.index view. <cfoutput>#prc.message#</cfoutput>

/views/viewlets/userinfo.cfm

`
Your username is #prc.username#.

`

/layouts/main.cfm

`

main layout
#renderView()#
#runEvent("viewlets.userinfo")#
`

What am I missing? A sample working code to demonstrate viewlets would be helpful. Thank you.

This part

#runEvent("viewlets.userinfo")#

and this part

component {
function userinfo(event, rc, prc) {
prc.username = “jsmith”;
return renderView(view=“viewlets/userinfo”);
}
}

When you call a handler with runEvent() and use event.setView or renderView() you can end up with views that you don’t want.

If you want to do something like this, create an API that is only accessible to anything that isn’t going to set a view, then refactor your code to do something like this.

component {
function userinfo(event, rc, prc) {

wrapperToGetUserInfo();
return renderView(view=“viewlets/userinfo”);
}

function wrapperToGetUserInfo(event, rc, prc) {

prc.userinfo = wrapperToGetUserInfo();
}

}

Then in your viewlett

#runEvent("viewlets.wrapperToGetUserInfo")#

Notice how I have refactored the event handler to remove the renderview()!!!

Also it might help to think of viewletts like widgets, no matter what the widgte becomes the container and then they do Ajax calls to get the data they need, viewletts are the same they already contain the view all they need now is to retrieve the data, either via models or other events.

It is also maybe good practice to refactor your code in this manner, especially if you plan to support Restful or other RPC type calls, that would allow you to keep your code duplication to a state of zero duplication.

Andrew, thanks for answering my questions and giving some advanced techniques. Would you mind take a look viewlets description on http://wiki.coldbox.org/wiki/Layouts-Views.cfm#Viewlets_(Portable_Events)? It seems pretty straight forward, but I couldn’t make the sample code work as I posted on https://groups.google.com/d/msg/coldbox/fow9lYo_cM4/Hp7Dld2Rn1EJ. Thanks again!

You know, I can’t actually see anything wrong with that!

Luis, Brad & Joel might need to pipe in here. My guess something has changed since the docs where written, could you tell us what version of ColdBox you’re using?

I am running ColdBox 3.8.1 on Railo 4.2.1.
Would you make your solution on https://groups.google.com/d/msg/coldbox/fow9lYo_cM4/jYpRDPGYD7EJ a bit clear? The wrapper looks like a recursive to me. :slight_smile:

There is no recursive going on there, all I am doing is this for the real event handler.

function userinfo(event, rc, prc) {

wrapperToGetUserInfo();
return renderView(view=“viewlets/userinfo”);
}

All I have done, is remove the code that is going to be duplicated to a separate method/function and called it in the handler above. Then the method looks like this, it is bare bones but has enough to understand it.

function wrapperToGetUserInfo(event, rc, prc) {
prc.userinfo = wrapperToGetUserInfo();

}

You might need to share your code. I just tried the exact code sample that’s in our docs and it worked perfectly. There is nothing wrong with it.

I posted my sample app on GitHub and ForgeBox so you can easily try it out. Install CommandBox if you are not already using it ( http://www.ortussolutions.com/#download )

Run the following commands from the interactive shell to download and and install my viewlet sample app and run it on your local machine (no web or CF server setup is necessary)

mkdir testsite
cd testsite
install coldbox-viewlet-sample
start

Let me know if you have more questions.

Thanks!

~Brad

Brad,

Thanks for the complete viewlet sample code. When I compared mine with yours, the only difference is you use composition in the bootstrapper; and mine used inheritance. So, the viewlet is working properly on with composition, but not with inheritance.

Anyway, thanks again everyone for helping me!

Hi Laksma, that shouldn’t make any difference at all. In fact, I just tested it using inheritance and my example site still runs fine. You can do it yourself. Just edit the Application.cfc and replace the contents of the entire file with this text:

component extends=‘coldbox.system.Coldbox’ { }

If you code is behaving differently, there must be something else different with your code. Perhaps, you can create a sample application of your own that exhibits this behavior so we can see it.

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 able to narrow down the problem. My bootstrapper extends from:

component extends=‘coldbox.system.mvc.Bootstrap’ { }

I got this from /ApplicationTemplates/lite/Application.cfc (inheritance version).

Ahh, you’re on ColdBox Lite-- that makes sense. Your behavior definitely seems like a bug, but to be honest ColdBox Lite has now gone away since ColdBox 4.0 is the new stripped-down core and everything has been extracted into modules. If I were you, I would just change the bootstrap over to use the full ColdBox framework.

Thanks!

~Brad

ColdBox Platform Evangelist
Ortus Solutions, Corp

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