preRenderView-Event triggered before an action (commandbutton) - jsf-2

I am in a little bit of trouble with my preRenderView-Event. My page also uses a commandbutton to submit data but unfortunately the preRenderView-Event is always called before the buttons action is invoked.
The preRenderView-Event is responsible for loading data from a service. Since the page is simple and doesnt have to store any data I dont need any Session or ViewScoped-Beans.
As far as I understood the event is called in the Render-Response-Phase and the action in the button should happen somewhat earlier.
<h:body>
<f:metadata>
<f:viewParam name="id" value="#{bean.id}" converter="converter.SetOfLongConverter"/>
<f:event type="preRenderView" listener="#{bean.initializeData}" />
</f:metadata>
<ui:composition template="/META-INF/templates/myTemplate.xhtml">
<ui:param name="title" value="#{bean.title}"/>
<ui:define name="content">
<h:outputText value="#{bean.description}" />
<h:form>
<h:panelGrid columns="2">
<h:outputLabel value="Model" for="model" />
<h:inputText id="model" value="#{bean.model}" />
<h:outputLabel value="Manufacturer" for="manufacturer" />
<h:inputText id="manufacturer"
value="#{bean.manufacturer}" />
<h:outputLabel value="Year" for="year" />
<h:inputText id="year" value="#{bean.year}" />
</h:panelGrid>
<h:commandButton value="Create" type="submit" action="#{bean.create}" rendered="#{bean.createMode}"/>
<h:commandButton value="Save" type="submit" action="#{bean.save}" rendered="#{!bean.createMode}" />
</h:form>
</ui:define>
</ui:composition>
</h:body>
I added some Console-Messages to verify when the method in the bean is called and when I have the preRenderView-event it never happens.
Any advice what I am doing wrong here?

The <f:metadata> has to go inside <ui:define> of an <ui:composition>.
See also <f:metadata> tag documentation (emphasis mine):
Declare the metadata facet for this view. This must be a child of the <f:view>. This tag must reside within the top level XHTML file for the given viewId, or in a template client, but not in a template. The implementation must insure that the direct child of the facet is a UIPanel, even if there is only one child of the facet. The implementation must set the id of the UIPanel to be the value of the UIViewRoot.METADATA_FACET_NAME symbolic constant.
The simple reason is because the metadata is supposed to be view-specific, not template-specific.
Update: it turns out that the action method is not invoked at all. You've there a rendered attribute on the command button which seems according the symptoms to be dependent on a request based variable instead of a view based variable. Putting the managed bean in the view scope should fix this problem. See also commandButton/commandLink/ajax action/listener method not invoked or input value not updated

Related

includeViewParams does not set values after validation

JSF 2.
A simple form with a single input that is validated. Using o:form in an attempt to fix the problem.
<f:view>
<f:metadata>
<f:viewParam name="info2" value="#{myClass.info2}" />
<f:viewParam name="info1" value="#{myClass.info1}" />
<f:event listener="#{myClass.init(}" type="preRenderView" />
</f:metadata>
<o:form includeViewParams="true">
<h:outputText value="Enter some info for #{myClass.info1}" />
<h:inputText id="input" value="#{myClass.info3}"
validator="myValidator" />
<br />
<h:commandButton action="#{myClass.action()}" value="Enter some info" />
<br />
<h:message for="input" />
<br />
<h:outputText value="#{myClass.info2}" />
</o:form>
</f:view>
Called with this URL
http://localhost:8080/test/test.xhtml?info1=hello&info2=there
When I put a value in the input field and the validation fails, the page comes back with
the same URL, but with both myClass.info1 and myClass.info2 set to null. It's great that
the URL is preserved, but it doesn't do much good if those parameters arent' being set in the
bean.
Why is that and how do I fix it?
Unfortunately, this is expected behavior. If validations phase fails, the update model values phase won't be executed. This not only applies to the input fields of the form, but also to the view parameters involved in the same request! Apparently, your bean is request scoped and then the view parameters set during the initial request will indeed be lost.
Your best bet is making the managed bean a #ViewScoped one instead and using <o:viewParam> instead to set the view parameter during the initial GET request only. You may only need to alter the init() method to skip the job when Faces#isPostback() returns true.

passing url param to backing bean method

I have the following code in my Facelet:
<ui:composition template="/templates/mastertemplate.xhtml">
<ui:define name="pageTitle">
<h:outputFormat value="#{msgs.productPageTitle}">
<f:param value="#{param.productName}"/>
</h:outputFormat>
</ui:define>
<ui:param name="categoryName" value="#{param.categoryName}"/>
<ui:define name="content">
<p>#{param.productName}</p>
<h:form>
<h:commandLink action="#{cartBean.addItemToCart(param.productName)}">
<f:ajax event="action" render=":cart :cartPrice" />
<h:graphicImage value="resources/img/addToCart.gif"/>
</h:commandLink>
</h:form>
</ui:define>
</ui:composition>
It prints the #{param.productName} as it should. The cartBean expects a String as argument for its addItemToCart method (I know this is terrible, but not my choice). I have set up a logger in my cartBean and it tells me that the parameter is not coming through, it is empty.
If I do the following:
<h:commandLink action="#{cartBean.addItemToCart('someProductName')}">
<f:ajax event="action" render=":cart :cartPrice" />
<h:graphicImage value="resources/img/addToCart.gif"/>
</h:commandLink>
I substitute the #{param.productName} for a string literal, it works fine. Why can't I pass the param value as argument? I get an EvaluationException which explains why my logger sees an empty string but I don't understand how I should do this then.
Not sure if it's possible that way but at the very least it seems to be bad practice. You'd insert the string to your backing back without any validation/conversion options.
I found a tutorial which explains what you should do to make it work here.

actionListener not called inside <c:if>

I have the following code, Using jsf2.2, primefaces 3.2.
My requirement is to update the Project depending on the updateFlag.
when i use c:if (xmlns:c="http://java.sun.com/jsp/jstl/core") like the following code the action Listener for the Update commandButton is not called. but if i use < p:panel rendered="#{projectBean.updateFlag}" > instead of < c:if > it works. Please help i dint get it, i think i should use c:if but its not working.
<p:dialog widgetVar="projectUpdate" id="projectUpdatePanel" modal="false" >
<p:panel>
<c:if test="#{projectBean.updateFlag == false}">
<h:outputText value="Project Title" />
<p:inputText disabled="true" value="#{projectBean.selectedProjectDo.projectTitle}" />
<p:commandButton value="Update" disabled="true" />
<p:commandButton value="Cancel" actionListener="#{projectBean.cancelUpdate}" />
</c:if>
<c:if test="#{projectBean.updateFlag == true}">
<h:outputText value="Project Title"/>
<p:inputText value="#{projectBean.selectedProjectDo.projectTitle}" />
<p:commandButton value="Update" actionListener="#{projectBean.updateProject}" />
<p:commandButton value="Cancel" actionListener="#{projectBean.cancelUpdate}" />
</c:if>
</p:panel>
</p:dialog>
You better just use it the following way (put a condition on the disabled attribute)
<p:panel>
<h:outputText value="Project Title"/>
<p:inputText disabled="#{not projectBean.updateFlag}"
value="#{projectBean.selectedProjectDo.projectTitle}" />
<p:commandButton disabled="#{not projectBean.updateFlag}" value="Update"
actionListener="#{projectBean.updateProject}" />
<p:commandButton value="Cancel" actionListener="#{projectBean.cancelUpdate}" />
</p:panel>
In general : don't use JSTL tags unless you really need them...
This is a classic example of non-DRY code, which is bad. Daniel shows perfectly how to make it DRY, however he didn't explain the cause of your problem.
Based on the problem symptoms, this will happen when #{projectBean} is a view scoped bean. View scoped beans are stored in the JSF view state. So, view scoped beans are only available after restore view phase. However, JSTL tags runs during restore view phase, while the view scoped beans are not available yet. This causes creation of a brand new view scoped bean instance, which is then later replaced by the real view scoped bean which was stored in the restored JSF view state. The brand new and separate view scoped bean which is used by JSTL will have all its properties set to default and thus the block which has updateFlag=false will always be invoked.
See also:
JSTL in JSF2 Facelets... makes sense?

Create new data objects with a popup panel fails

Here I am again with a JSF problem, this time it is more about richfaces (4.2.1 final, JSF 2). I have an eytended DataTable and want to add new items. There ist the List of Journey-objects, every attribute have getter and setter. The table is created well (there are already some items in the list). And now I click the "add new item" button:
<a4j:commandButton ajax="true" value="Neue Fahrt hinzufügen"
actionListener="'{editorBean.prepareCreateJourney}" render="createJourneyPopupForm"
oncomplete="#{rich:component('createJourneyPopup')}.show()" />
The editorBean is SessionScoped, the method is properply called and create a new object of Journey called currentJourney. A popup comes up and should allow me to insert some input:
<rich:popupPanel id="createJourneyPopup" modal="true">
<h:panelGrid id="createJourneyPopupForm" columns="3">
<h:outputLabel for="currentId" value="ID" />
<h:inputText id="currentId"
value="#{editorBean.currentJourney.journeyNumber}" />
<rich:message for="currentId" />
[...and more...]
</h:panelGrid>
<a4j:commandButton value="Save"
execute="currentId currentTrainType operator">
<f:ajax event="click" listener="#{editorBean.doCreateJourney}"
render=":vmsEditorForm:resultTable" />
<rich:componentControl target="createJourneyPopup" operation="hide" />
</a4j:commandButton>
<a4j:commandButton value="Abbrechen"
onclick="#{rich:component('createJourneyPopup')}.hide();" />
</rich:popupPanel>
When i clicked the button, the method doCreateJourney is called, but the currentJourney is empty. It is the default Journey object after creating it. No setter was called, do a hint on the inputfields.
I checked the names twice, there are getters and setters for alle needed objects. I tried to change the scope, but no effect. Objects are the same, in the prepare method i created Journey(id=151) and in the save method it is still Journey(id=151).
What is going on here? I can't be this difficult to make some dialogs to create and edit data objects. Thank you for listening and for your help!
You need to wrap both your inputs and your commandButtons in a form in order to correctly submit the data.
<rich:popupPanel id="createJourneyPopup" modal="true">
<h:form>
... the content of your popupPanel
</h:form>
</rich:popupPanel>
Regards,

Java facelets dynamic loading and composite component attributes

Currently I'm trying to implement webpart technology with JavaServer Faces 2.0 with Facelets view technology for educational purposes. I have created facelet templates, facelet custom components and made a few facelet "template" clients. But in one thing I'm stuck. I can't dynamically load controls and put them cc:attributes.
If I have a page for example with static text or bind it with ManagedBean the property ui:include everything works well.
<ui:define name="right-column">
right-column asd
<h:link outcome="asdf" value="link_get">
<f:param name="aa" value="123" />
<f:param name="a" value="123 dd + 20" />
</h:link>
<h:commandLink action="asdf?faces-redirect=true" value="asdf">
<f:param name="aa" value="123" />
</h:commandLink><br />
<ui:include src="./resources/Controls/CategoryTree.xhtml"/><br />
This works even if I put src with MenageBean property.
<ui:include src="#{browseProducts.incudePath}"/>
</ui:define>
Here is my facelet control (data binding is inside this control within #{TreeBean.root}:
<!-- NO INTERFACE -->
<cc:interface>
</cc:interface>
<!-- IMPLEMENTATION -->
<cc:implementation>
<!-- This is a very simply scaffolding for Category Three Control.
-->
<p:tree value="#{TreeBean.root}" var="node"
expandAnim="FADE_IN" collapseAnim="FADE_OUT">
<p:treeNode>
<h:outputText value="#{node}" />
</p:treeNode>
</p:tree>
</cc:implementation>
But I have problem when ui:include points to a control with cc:attribute. I don't know how to initialize this attribute from backing bean and do "stuff".
For example I have this page:
<ui:composition xmlns:ui="http://java.sun.com/jsf/facelets"
template="./resources/layout/Template.xhtml"
xmlns:sc="http://java.sun.com/jsf/composite/Controls">
<ui:define name="right-column">
<sc:dummy ItemCount="10" />
<ui:include src="./resources/Controls/dummy.xhtml" />
</ui:define>
</ui:composition>
Here goes the composite control:
<cc:interface>
<cc:attribute name="ItemCount" required="true"
shortDescription="This attribute is meaningful " />
</cc:interface>
<!-- IMPLEMENTATION -->
<cc:implementation>
<!-- How to pass ItemCount to my dummy bean to create so many items in
list as ItemCount value -->
<ui:repeat value="#{dummy.dummyList}" var="dummyItem">
<h:outputText value="#{dummyItem}" />
</ui:repeat>
</cc:implementation>
And backing bean code:
public ArrayList<String> getDummyList() {
//Here I try to get dummy list work.
dummyList = new ArrayList<String>(getDummyCount());
for (int i=0;i< getDummyCount();i++){
dummyList.add(i + "" + i);
}
return dummyList;
}
How can this be done?
I think you have two problems:
calling a method with parameter from a composite component
specifying some parameter to an included page
For 1., since jsf 2, you could call the method directly, specifying the parameter (which should be part of method signature):
<ui:repeat value="#{dummy.getDummyList(cc.attrs.dummyCode)}" var="dummyItem">
<h:outputText value="#{dummyItem}" />
</ui:repeat>
But I suspect you are trying to use a backing for something that it isn't designed for. Maybe you'll be interested in writing backing java code for your composite component, which is different. It's difficult to master if you are a beginner, though. I'd first try to design my pages and bean interactions differently. I don't know which problem you are trying to solve, but at first look, this solution looks too complicated.
For 2., you should have a look at ui:param. A quick google search gives me this: http://www.jsfcentral.com/articles/facelets_3.html

Resources