Howto validate an entity shared over multiple tabs - validation

I am having an entity with many attributes which should be displayed in multiple tabs in a p:tabView. It might look like the following.
I have one h:form which surrounds the p:tabView. In the tabs I have a single p:message for every input element.
<p:column>
<p:outputLabel value="Name" for="name_input" />
</p:column>
<p:column>
<p:message for="name_input" display="icon" />
</p:column>
<p:column>
<p:inputText id="name_input" value="#{bean.person.name}">
<p:ajax /> <!-- put value into backingbean on tabchange -->
<f:validateRequired />
</p:inputText>
</p:column>
I have made the following observations.
1) Problem: validation is only executed in tabs which have been activated
If I switch to edit mode and the current tab has no validation errors and I do not change the tab, then my entity gets saved and validation error on other tabs are ignored.
If I switch to edit mode and navigate to a tab which has validation error and then navigate to the first tab with no validation error, then a vaidation error is displayed (but only from those tab, that I visited).
(I hope this is understandable, at least a little bit) It does not make a difference if I set dynamic=true/false and cache=false in the p:tabView.
2) Problem: no message icon on tab change
If I switch to edit mode and click on every tab so that every validation error are recognized (like in scenario b) I get a proper validation message (icon) and the p:inputText is displayed with a red border. So everything seems to be fine. But if I navigate to another tab with validation errors there is no message icon displayed, only the red border is around the particular p:inputText. As far as I would guess, the JSF lifecycle is executed on tab change but no validation takes place so for this lifecycle roundtrip everything is OK and the message icon disappears (on the other hand it is a mystery to me why the red border does not disappear...).
3) Problem: no visual hint in the tab
For the user experience I would very much like to have a visual hint (i. e. a red background on a tab-title) so that a user knows where the problems occur.
I have read Validating one form with multiple tabs, how to switch tabs without losing validation errors? Using Myfaces and Trinidad but neither the wizard (it is not a "wizardy" task it is just an edit of a big entity) nor the do-it-yourself-with-javascrip-and-css (main problem is the corporated identity I am using pretty often tabViews in other situations) is a good option for me.
Does anyone have a solution/hint for any of my problems?
I am using JSF 2.2, Primefaces 5.3.

OK, a colleague of mine came up with the answer.
First of all, my first two problems vanished into thin air. With the attributes dynamic="false" and cache="false" in the <p:tabView /> this works as desired (I do not know what I tested back then).
And the visual hint in the tab. There is a <f:facet name="title" /> which can be used to display the tab title and additional messages. The <p:message /> components are doubled, firstly inside the column at the input component and secondly in the title-facet. With a little CSS one can adjust the icons in the title at will.
<p:tabView dynamic="false" cache="false">
<f:facet name="title">
Address
<p:message for="name_input" display="icon" />
</f:facet>
...
<p:panelGrid>
<p:row>
<p:column>
<p:outputLabel value="Name" for="name_input" />
</p:column>
<p:column>
<p:message for="name_input" display="icon" />
</p:column>
<p:column>
<p:inputText id="name_input" value="#{bean.person.name}">
<p:ajax />
<f:validateRequired />
</p:inputText>
</p:column>
</p:row>
....
</p:panelGrid>
</p:tabView>

Related

JSF and primefaces p:booleancheckbox not rendering correctly

I have a strange behaviour in my code that for some reason I'm unable to solve.
I'm using PF4 and mojarra 2.1.28 running on jboss eap 6.4.
Here's the code
<p:column>
<f:facet name="header">
<p:selectBooleanCheckbox id="checkAll" value="#{backingBean.allowAll}">
<p:ajax listener="#{backingBean.confirmAllowAlla}" process="tablaDoc" update="tablaDoc :form1:facesMessages" onstart="mask();" oncomplete="unmask();" />
</p:selectBooleanCheckbox>
<p:outputLabel for="checkAll" value="Allow all" />
</f:facet>
<p:selectBooleanCheckbox id="checkTipo" value="#{tipoDocumento.allowed}" >
<f:param name="idTipoDocumento" value="#{tipoDocumento.idTipoDocumento}"/>
<f:param name="secuencia" value="#{tipoDocumento.secuencia}"/>
<p:ajax listener="#{backingBean.confirmChange(tipoDocumento)}" process="#this" update="tablaDoc :form1:facesMessages" onstart="mask();" oncomplete="unmask();" />
</p:selectBooleanCheckbox>
</p:column>
Getters and setters exist, backing bean is invoked as it should... apparently everything works but...
when I click in the booleanCheckbox placed in the header all the other checkboxes should be checked.
First time I click internally everything seems to go ok. Model is updated correctly and my datatable is updated accordingly but for the checks. Visually they are not checked (checked="checked" is missing in the output html) but all the expected behaviour is just fine. A button for each row is enabled/disabled and even if I add a column to display the internal value used for the check it renders the expected value.
If I uncheck the main checkbox and check it again, normal behaviour is restored and the checks for each row start rendering ok (checked="checked is in the output html).
I cannot modify my DTOs so I cannot implement SelectableDataModel from PrimeFaces.
Any ideas?

malformedXML: During update: outerTab:j_idt185 not found; iframe id="JSFFrameId"

I have a form with a PrimeFaces selectOneMenu which, when the user selects an option, I want to refresh a DataTable in the same form with different data. When I select an option I get a Javascript popup that says "malformedXML: During update: outerTab:j_idt185 not found" with no DataTable refresh and on inspecting the source I see an invisible iframe at the bottom of the page with id="JSFFrameId" that contains an element <partial-response> that in turn contains an element <update id="outerTab:j_idt185" ...> and this contains an element <![CDATA[<div id="outerTab:j_idt185" class="ui-messages ui-widget" aria-live="polite"></div>]]>. I think this references my <messages> tag, but nothing in the backing bean creates a message, and I do see an element in the page source <div id="outerTab:facilitatorTestsForm:j_idt113" class="ui-messages ui-widget" aria-live="polite"></div> where the messages should be, so the messages tag is indeed rendered. I can find no element with an ID containing "j_idt185" and apparently neither can some Javascript.
The "outerTab" in the IDs is a PrimeFaces TabView that contains all this stuff.
A page refresh causes the update to happen and the DataTable shows the correct data for the selected SelectOneMenu option.
I have found several posts by balusC where some element that is updated by an ajax call has a rendered value that makes it not render and therefore unable to be found when the update is called for. The target of my update (the DataTable) has no rendered attribute and is visible all the time, so this is a different problem. Other posts speak to a bug in earlier versions of PrimeFaces (I am using 6.1). I cannot figure out why this error occurs.
#Kukeltje kindly pointed me to several posts showing that using an encoding type of multipart/form-data in a file-upload component or a form submit can cause this problem but my page has neither of these.
Here is an excerpt of my page:
<div align="center">
<h:form id="facilitatorTestsForm">
<p:messages for="testBeanMessages" showSummary="true" showDetail="true" globalOnly="true" escape="false" autoUpdate="true" />
Tests for which event?
<p:selectOneMenu value="#{testBean.selectedEventId}" style="top: 7px; ">
<f:selectItem itemLabel="All Tests" itemValue="" />
<f:selectItems value="#{testBean.facilitatorEvents}" var="event" itemValue="#{event.id}" itemLabel="#{event.name}" />
<f:ajax update="facilitatorTests" />
</p:selectOneMenu>
<p:commandButton value="Add a New Test" style="margin: 20px;" oncomplete="PF('newTestDialog').show();" actionListener="#{testBean.createEmptyNewTest}" immediate="true" />
<p:dataTable var="test" value="#{testBean.testsForFacilitator}" rowIndexVar="index" id="facilitatorTests" widgetVar="facilitatorTests" selectionMode="single" selection="#{testBean.selectedTest}" rowKey="#{test.id}">
<p:ajax event="rowSelect" oncomplete="PF('facilitatorEditTestDialog').show(); " update="#form:facilitatorEditTestDialog" />
<p:column>#{index + 1}</p:column>
<p:column headerText="Test" sortBy="#{test.name}" width="40%"><h:outputText value="#{test.name}" /></p:column>
<p:column headerText="Tester" sortBy="#{test.tester.fullname}"><h:outputText value="#{test.tester.fullname}" /></p:column>
<p:column headerText="Manager" sortBy="#{test.manager.fullname}"><h:outputText value="#{test.manager.fullname}" /></p:column>
<p:column headerText="Event" sortBy="#{test.event.name}"><h:outputText value="#{test.event.name}" /></p:column>
<p:column headerText="Functional Area" sortBy="#{test.functionalArea.name}"><h:outputText value="#{test.functionalArea.name}" /></p:column>
<p:column headerText="Complete" width="150" sortBy="#{test.completionDate}"><h:outputText value="#{test.completionDate == null ? 'Not Completed' : test.completionDate}"><f:convertDateTime pattern="M/d/yyyy hh:mm a" /></h:outputText></p:column>
<p:column id="delete" style="text-align: center; vertical-align: middle; min-width: 54px; ">
<p:commandButton update="facilitatorTests" process="facilitatorTests" icon="ui-icon-close" actionListener="#{testBean.deleteTest(test.id)}"
title="If the test has not been completed, it will be deleted permanently. Otherwise it will be archived."/>
</p:column>
</p:dataTable>
<... a few dialogs with conditional rendering ...>
</h:form>
</div>
I have tried different targets for the selectOneMenu update attribute and it does not change the behavior so I believe it is correct.
Primefaces 6.1
Mojarra JSF API & IMPL 2.2.4
EL 3.0.0
Tomcat 7
Is this a JSF bug? Thanks for any help you can offer.
Found the solution. Thanks to #Kukeltje for staying with me through this even if he did downvote my question for not having enough info :)
It comes back to #BalusC's posts about not rendering the target of an ajax update. In this case I had several PrimeFaces TabView tabs containing <p:messages> tags with autoUpdate="true", and the tabs are shown/hidden depending on the role of the user. When I removed autoUpdate="true" from these messages tags the problem went away. Apparently every time I did an ajax post, even if I had partial submit limited to rendered subelements of the current visible tab, autoUpdate causes JSF to try to update the messages tags in the unrendered tabs and of course they cannot be found.
The way I found this was to put id attributes EVERYWHERE, on every element in my forms. Then the Javascript error pointed me to a named (id'd) element, rather than one with an automatically assigned ID that I could not trace, and when I saw "autoUpdate" the light bulb came on. Moral: put ids on EVERYTHING.
I hope this helps someone with the same symptom to look for autoUpdate everywhere.
And #Kukeltje you were right that my post had inadequate information - without the enclosing tab tags with their rendered attributes you could not have seen the problem. Since they were in another template that ui:includes the forms I did not think they were relevant. Wrongo!

Fire AJAX twice from same component (simultaneously)

Well, I want to fire AJAX from one component but for two destinations, let some code clear out what I mean with that :
<p:growl id="growl" showDetail="true" sticky="true" />
<p:inputText value="#{someBean.someProperty}" >
<f:ajax event="blur" render="growl" listener="#{someBean.someListenerMethod}"/>
<f:ajax event="blur" render="updatable" />
</p:inputText>
<h:outputText value="#{someBean.someProperty}" id="updatable" />
So once the blur event occures, the <h:outputText> and the <p:growl> will be "AJAXed" (in primefaces tongue : updated). I had this example in mind and anther one that replaces the second <f:ajax> with an update attribute in <p:inputText>, but neither done me good.
Hopefully, you're going to know better and aid me solving this out, thanks in advance.
You can add more than one item inside the render attribute :
<f:ajax event="blur" render="growl updatable" listener="#{someBean.someListenerMethod}"/>

Primefaces components to update when commandButton is clicked

Lets say we have button
<h:form>
<p:commandButton id="refreshButton" value="refresh all depending components"/>
</h:form>
Along the way I will add components that should be updated when the button is clicked. So using the update="text1,text2" will not suffice, as text3 might be added later on and shouldn't require changes to the refresh button.
<h:outputText id="text1" value="{bean.someValue1}></h:outputText>
<h:outputText id="text2" value="{bean.someValue2}></h:outputText>
... and later ...
<h:outputText id="text3" value="{bean.someValue3}></h:outputText>
What I want to do is to bind the components to the button, rather than the button having dependencies to the components
What you're asking is not possible. As least, not using the standard ways in the view.
But what is possible is to reference a common parent instead.
<p:commandButton ... update="texts" />
...
<h:panelGroup id="texts">
<h:outputText id="text1" ... />
<h:outputText id="text2" ... />
...
<h:outputText id="text3" ... />
</h:panelGroup>
Depending on the concrete functional requirement, which isn't clear from the question, there may be better solutions. But if it boils down to laziness and/or avoiding to "forget" to change the button, then I'm afraid that there's no magic fix.
I did a a temporary quickfix by using
<p:outputPanel autoUpdate="true">
<h:outputText id="text3" ... />
<p:outputPanel />
Guess it performance wise is not perfect, as it will be updated on all ajax events and not just the ones I'm interested in. But luckily this component is interested in all of them any ways, so it is not a problem atm.

how does PrimeFaces' AjaxStatus work?

I am trying to understand PrimeFaces' AjaxStatus indicator.
There are two facets - start and complete.
Can anybody tell me, what really determines start and complete.
I am just trying to make the indicator GIF image visible when user clicks a button and make it disappear when he click another button.
If whatever I am trying to achieve does not make any sense, an explanation would be really helpful.
Thanks.
ajaxStatus component works with globally set components. This means that a commandButton with the attribute:
global="true"
will trigger a process that will make use of ajaxStatus component (will update it's output).
This said, ajaxStatus start facet will work when the listener method is called and will update when the complete status is reached, this is, when the lifecycle of the call ends.
As I understand, this will not take care of the success or failure of the process. For this statuses, you also have other facets available: error and success.
<p:ajaxStatus>
<f:facet name="prestart">
<h:outputText value="Starting..." /> </f:facet>
<f:facet name="error"> <h:outputText value="Error" />
</f:facet>
<f:facet name="success"> <h:outputText value="Success" />
</f:facet>
<f:facet name="default"> <h:outputText value="Idle" />
</f:facet>
<f:facet name="start"> <h:outputText value="Please Wait" />
</f:facet>
<f:facet name="complete"> <h:outputText value="Done" />
</f:facet>
</p:ajaxStatus>
There is an ajax loading gif bundled with PrimeFaces:
<h:graphicImage library="primefaces" name="jquery/ui/ui-anim_basic_16x16.gif" />

Resources