4

I have a page where I want to include a part of the page (footer in this instance) dependant on values given from a view parameter.

I have my ViewScoped backing bean initializing on preRenderView

<f:metadata>
    <f:viewParam name="racecode" value="#{displayResults.racecode}" />
    <f:event type="preRenderView" listener="#{displayResults.init}" />  
</f:metadata>

This queries the database to get the name of the footer to be included. This then, is used in this fashion :

<h:panelGroup id="customFooter" display="block">
    <ui:include src="#{displayResults.customFooter}" />
</h:panelGroup>

This always gives me a missing page. But if I enter the page name manually it works. Same if I replace the ui:include with an h:outputText.

I understand that it has something to do with the phases of JSF and that at the time the ui:include is done, the value is not set yet. (reading up and better understanding the phases is something on my TODO list).

The question remains. How can I get something of the sort done. Have a bean use the viewParam, query the database and use that value in a ui:include?

blo0p3r
  • 6,392
  • 7
  • 47
  • 67

2 Answers2

3

@wemu has already explained the cause. The <ui:include src> is evaluated before init() method is called. His proposed <f:phaseListener> solution is however clumsy.

Just use @ManagedProperty/@PostConstruct on a @RequestScoped bean.

@ManagedProperty("#{param.racecode}")
private String racecode;

@PostConstruct
public void init() {
    // ...
}
BalusC
  • 992,635
  • 352
  • 3,478
  • 3,452
  • This makes total sense. I'm often concerned about best practices and stuff like this (OCD a bit I think). Now let's say I am loading two beans for this one page load, and this creates an extra call to the databse. Of course, I have the information I need to make this work. Would it be better to change my current `preRenderView` completely to this and have all at one location? Also, why `@RequestScoped` here? – blo0p3r Oct 04 '12 at 14:45
  • 2
    You could inject beans in each other by [`@ManagedProperty`](http://balusc.blogspot.com/2011/09/communication-in-jsf-20.html#InjectingManagedBeansInEachOther). The `@RequestScoped` is mandatory for 2 reasons: 1) the `#{param}` is request scoped 2) the `` is a [taghandler](http://balusc.blogspot.com/2011/09/communication-in-jsf-20.html#ViewScopedFailsInTagHandlers). So `@ViewScope` is absolutely not an option. – BalusC Oct 04 '12 at 14:48
  • This did work for what I wanted to do. But seems to have let to another issue. I have my resquest scope and view scope bean both on the same page. When I trigger an actionListener on my page that is supposed to trigger a method in my viewScope bean, it only calls the request scope bean and never makes it to the method in question. – blo0p3r Oct 04 '12 at 19:56
  • There are indeed prolems with regard to using forms in combination with dynamic includes. See this question+answer for more detail: http://stackoverflow.com/questions/11408130/jsf-commandbutton-works-on-second-click – BalusC Oct 04 '12 at 20:17
  • Similar problem, but the solution did not work. I now have the same `displayResults` set to `viewScoped` and a new `customResults` set to `requestScoped`. This customResults, gets the info for my includes and works fine. But when I click a listener within the page, all it does is call the constructor to the `customResults` and never the method `displayResults` method being called by the action. – blo0p3r Oct 05 '12 at 12:47
1

PreRenderView listeners are called within the RenderResponsePhase, before components are rendered BUT AFTER the TagHandlers are called. This means that TagHandlers will NOT see data initialized within a PreRenderView event.

If you are using a <ui:include value="#{myBean.myViewId}" /> to dynamically switch an include you can't use a PreRenderView event listener to set the myViewId property of myBean.

If you need to do that use a <f:phaseListener>.

wemu
  • 7,236
  • 3
  • 30
  • 51
  • I understand what you are saying. But as I understand and according to [this link](http://stackoverflow.com/questions/9844526/when-to-use-prerenderview-versus-postconstruct) I need to go through the `preRenderView` as the `myViewId` is dependent on the `viewParam` --> so I still need to "wait" till the update model values phase? – blo0p3r Oct 04 '12 at 14:14
  • yes I would think so too but to believe it myself I would need to give it a try (stuff like this confuses me). – wemu Oct 04 '12 at 14:31