actionListener not called inside <c:if> - jsf-2

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?

Related

<c:if><c:otherwise> does not work, both conditions evaluate like true

I am trying to toggle between two different command buttons depending on whether a list contains the given item ID:
<c:if test="#{roomServiceManagerBean.holdinghotelvilla.contains(hotel.hotelvillaId)}">
<p:commandButton ajax="true" id="commanddeactivate" update=":roomserviceForm:hoteltable,:roomserviceForm:msgs" actionListener="#{roomServiceManagerBean.deactivateServiceForHotel(hotel.hotelvillaId)}" icon="ui-icon-radio-off" type="submit" value="Remove Service">
<f:param name="roomserviceid" value="#{roomServiceManagerBean.roomServiceId}" />
</p:commandButton>
</c:if>
<c:otherwise>
<p:commandButton id="commandactivate" update=":roomserviceForm:hoteltable,:roomserviceForm:msgs" actionListener="#{roomServiceManagerBean.activateServiceForHotel(hotel.hotelvillaId)}" icon="ui-icon-radio-on" type="submit" value="Provide Service">
<f:param name="roomserviceid" value="#{roomServiceManagerBean.roomServiceId}" />
</p:commandButton>
</c:otherwise>
However, it fails and the both buttons appear. How is this caused and how can I solve it?
The <c:if> will in this construct fail if #{hotel} is not available during view build time but only during view render time (e.g. because it's definied as <p:dataTable var>). The <c:otherwise> is completely displaced here. It belongs to a <c:choose><c:when>. Technically, you should be using <c:if> instead with a negation in the test. Or, you should be replacing the first <c:if> by a <c:when> and wrap the whole thing in <c:choose>. However that would still fail if #{hotel} is not available during view build time.
Just use JSF component's rendered attribute instead.
<p:commandButton ... rendered="#{roomServiceManagerBean.holdinghotelvilla.contains(hotel.hotelvillaId)}">
...
</p:commandButton>
<p:commandButton ... rendered="#{not roomServiceManagerBean.holdinghotelvilla.contains(hotel.hotelvillaId)}">
...
</p:commandButton>
See also:
EL expression in c:choose, can't get it working
JSTL in JSF2 Facelets... makes sense?

ignoreValidationFailed doesn´t work inside ui:repeat

I´m using o:ignoreValidationFailed, but it doesn´t work inside the ui:repeat. When I do the same outside, it works! I tried with mojarra ans MyFaces... I´m using primefaces. If there is another way to skip the validations only for one button...
<o:form id="rateplanEditByPeriod" prependId="false">
<p><p:messages id="mensagensDlg"/></p>
<p:tabView id="tabs">
<p:tab title="Cancelamento" id="tabCanc">
<h:panelGrid id="cancelationsTable" columns="2" cellpadding="10px" columnClasses="alignTop,alignTop">
<ui:repeat id="repeat" var="rest" value="#{rateplanByPeriodManaged.rateplanByPeriod.restriction.restTypeCancelation.restTypeCanConfs}" >
<h:panelGrid columns="8">
<p:inputText id="penaltyValue_#{loop.index}" value="#{rest.penalityValue}" style="width:28px" label="Valor" title="Valor" disabled="#{rest.noCancel}" required="true"/>
<p:commandLink id="add_#{loop.index}" actionListener="#{rateplanByPeriodManaged.addCancConf}" update=":rateplanEditByPeriod:tabs:cancelationsTable" partialSubmit="true" process=":rateplanEditByPeriod:tabs:cancelationsTable" value="+">
<o:ignoreValidationFailed />
</p:commandLink>
<p:commandLink actionListener="#{rateplanByPeriodManaged.removeCancConf(rest)}" value="-" update=":rateplanEditByPeriod:tabs:cancelationsTable" partialSubmit="true" process=":rateplanEditByPeriod:tabs:cancelationsTable">
<o:ignoreValidationFailed />
</p:commandLink>
</h:panelGrid>
</ui:repeat>
</h:panelGrid>
</p:tab>
</p:tabView>
<p:commandLink styleClass="button" onclick="dlgEdit.hide()" immediate="true" update=":msgsPanel">#{msgs['inventory.editByPeriod.cancel']}</p:commandLink>
<p:commandLink styleClass="button" actionListener="#{rateplanByPeriodManaged.editByPeriod(loginManaged.hotelSelected)}" oncomplete="if (!args.validationFailed) {dlgEdit.hide(); updateAllSearches(); updateAllNotifications();}" update="mensagensDlg, tabs" >#{msgs['inventory.editByPeriod.confirm']}</p:commandLink>
</o:form>
I have faced the same issue but with p:datatable
I solved it with
1- add a condition to the required field to know if the ajax come from submit button or not
as #Camilla said.
required="#{!empty param['trans_desc_form:savetransid']}"/>
trans_desc_form is the entire form id and savetransid is the submit button save id
2- I removed #NotNull from my JPA entity which force the validation
#JoinColumn(name = "ITEMNO", referencedColumnName = "ITEMNO")
#ManyToOne(optional = false, fetch = FetchType.LAZY)
//#NotNull
private Item item;
I have created a question for this issue
ignoreValidationFailed doesn´t work inside p:dataTable
I don´t know if it´s the best aproach but it worked for me...
<h: inputText id="text1" value="" required="#{!empty param['formName:btnSave']}" />
This is not the right way to have a "Cancel" button.
Just put process="#this" in the <p:commandLink>, or if you don't need to do any business logic, make it a normal <h:link> which reloads the page (and thus implicitly recreates the request/view scoped bean).
As to <o:ignoreValidationFailed> the failure in <ui:repeat> on its own, please create an issue.

Constructor of a viewScoped class invoked twice

I've been struggling with this for two days with no success and I think it's already time to ask for your help. But first of all, this is what I'm using:
JSF 2 Mojara 2.1.1
Primefaces 3.4.2
Netbeans 7.1.1
Tomcat 7.0.37
And now, the problem: I have a main page which is composed by several other pages using several <ui:include .. /> tags, like this:
<ui:composition template="/resources/templates/template1.xhtml">
<ui:define name="appData">
<p:panelGrid columns="1" id="contenidoAplicacion" styleClass="noborder">
<h:form id="fNewPerson">
<p:panel header="New employee" style="min-height:40em">
<ui:include src="./forms/personal.xhtml" />
<p:accordionPanel styleClass="noborder" activeIndex="3">
<p:tab id="tabSomeData" title="Identidad profesional" >
<ui:include src="./forms/formSomeData.xhtml" />
</p:tab>
....
....
</ui:define>
</ui:composition>
The personal.xhtm file looks like this:
<p:panelGrid>
<p:row>
<p:column >
<h:outputLabel value="Field1"/>
<p:inputText label="Field1" id="field1" value="#{dataBacking.selectedPerson.field1}" tabindex="1"
required="true" size="10" >
<f:convertNumber for="field1" integerOnly="true" groupingUsed="false"/>
</p:inputText>
<p:inputText id="field2" value="#{dataBacking.selectedPerson.field2}" tabindex="2" required="true" size="1" maxlength="1" >
<p:ajax event="keyup" listener="#{dataBacking.check}"
process="field1 field2" partialSubmit="true"
update="field1 field2 photo"/>
</p:inputText>
</p:column>
<p:column rowspan="5" >
<p:graphicImage id="photo" value="#{dataBacking.selectedPerson.photo}" width="90" />
</p:column>
</p:row>
...
</p:panelGrid>
The check() method in the dataBacking class is irrelevant because it only checks if the field1 and the field2 meet some rules and it works properly. The problem comes when the main page is loaded for the first time. In that case, the <p:ajax /> component in personal.xhtml doesn't work. I have to reload the page (simply by pressing the F5 key) and this time it works as it would be expected.
I've been changing some attributes of the component, but nothing seems to work. I really don't know what else to do. Any kind of help will be apreciated.
EDITED. After one more day, I think the problem has nothing to do with Primefaces ajax component, as the title of the question suggested. I've come to this conclusion through these two facts:
The behaviour with the <f:ajax .../> component remains the same.
I've figured out that the view relative to the first time I load the page is not persisted. I'll try to explain myself.
The DataBacking class has defined its scope as view so that the page can "see" all the attributes and methods during the time it's been shown to the user. However, I've noticed that the constructor is called twice: the first time the page is loaded (and then, none of the methods of the class are successfully invoked) and when I refresh the page. In this last case, the behaviour of both the page and the class is the expected one.

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,

preRenderView-Event triggered before an action (commandbutton)

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

Resources