Primefaces tabview activeIndex not updated on server - primefaces

Porting my web-application to a newer version I faced an odd disfunction in behaviour of activeIndex from p:tabView UI component. Shortly said: In my existing web-application it all works fine, in my newer version activeIndex is not beeing updated on the backing bean. Both web-applications use the same code! And also the same java-libraries and Primefaces version (8.0).
xhtml code is:
<p:tabView id="TVMR"
styleClass="menuRight zw-fontFamily zw-green zw-fontNormal"
dynamic="true" cache="false" orientation="left"
widgetVar="tabViewMenuRight"
style="border: 0px solid black; padding: 0px !important;"
activeIndex="#{accViewer.tabIndex}">
<p:tab title="" disabled="true" id="tab0">
</p:tab>
<p:tab title="Accommodatie" id="tab1">
</p:tab>
<p:tab title="Location" id="tab2">
</p:tab>
......
<p:ajax event="tabChange" listener="#{accViewer.onChange}"
update="#this, accomMenuPanel, TVMR, cac010, cac020, cac030, cac040"
resetValues="true" />
</p:tabView>
java code is:
public void setTabIndex(int tabIndex) {
System.out.println(thisClassName + ": setTabIndex (1) - " + tabIndex);
this.tabIndex = tabIndex;
}
public void onChange(TabChangeEvent<TabChangeEvent> event) {
System.out.println(thisClassName + ": onChange (1) - " + event.getTab().getId());
if (AppUtils.isInteger(event.getTab().getId().substring(3))) {
int i = Integer.parseInt(event.getTab().getId().substring(3));
if (this.tabIndex != i) {
System.out.println(thisClassName + ": onChange (2) - " + i);
setTabIndex(i);
}
}
}
On my newer website I had to build a workaround to get everything good functioning again. So in case of when the automatic tabIndex is not beeing updated by p:tabView, It will be updated by onChange(TabChangeEvent event). Here you see the results of both web-applications compared:
Existing web-app shows:
viewer.AccViewer: setTabIndex (1) - 4
viewer.AccViewer: onChange (1) - tab4
New web-app shows:
viewer.AccViewer: setTabIndex (1) - 1
viewer.AccViewer: onChange (1) - tab4
viewer.AccViewer: onChange (2) - 4
viewer.AccViewer: setTabIndex (1) - 4
My configuration is:
Eclipse 18-12;
JDK v11.0;
Apache Tomcat (TomEE)/9.0.41 (8.0.6);
JSF2.3;
myfaces2.3;
Primefaces 8.0;
If anyone could give a hint or explanation of what may cause this unexpected behaviour, I would very much apreciate it! Solving this type of disfunctioning is much time consuming and unless I made some mistake myself, I feel that Primefaces framework (which I find is a great engineered java UI-layer!) should be a bit more stable. Maybe Primefaces could investigate some time to get p:tabview tabIndex server update process reliable!?

Related

Primefaces steps skip validation on primefaces file uploader [duplicate]

since fileLimit doesn't exist in primefaces 3.4 anymore I'm trying a work around implementing a validator, the problem is that the method validate is never invoked. That's my Validator:
#FacesValidator(value ="fileLimitValidator")
public class FileLimitValidator implements Validator {
#Override
public void validate(final FacesContext context, final UIComponent component,
final Object value) throws ValidatorException {
final String fileLimit = (String)component.getAttributes().get("fileLimit");
final String size = (String)component.getAttributes().get("size");
if (fileLimit!=null && size!=null) {
if (Integer.valueOf(size) >= Integer.valueOf(fileLimit)) {
FacesUtils.throwErrorExceptionFromComponent(component,"fichero_confidencialidad_error");
}
}
}
}
and in my facelet I've tried:
<p:fileUpload id="#{id}FileUpload"
fileUploadListener="#{bean[metodoTratarFichero]}" mode="advanced"
multiple="true" allowTypes="#{allowTypes}" showButtons="false"
update="#{id}ListaDocs #{id}MsgError" auto="true"
label="#{fileuploadmsg.label_boton}"
invalidFileMessage="#{fileuploadmsg.tipo_incorrecto}" >
<f:validator validatorId="fileLimitValidator"/>
<f:attribute name="fileLimit" value="#{fileLimit}"/>
<f:attribute name="size" value="#{listaDocumentos.size}"/>
</p:fileUpload>
and:
<p:fileUpload id="#{id}FileUpload"
fileUploadListener="#{bean[metodoTratarFichero]}" mode="advanced"
multiple="true" allowTypes="#{allowTypes}" showButtons="false"
update="#{id}ListaDocs #{id}MsgError" auto="true"
label="#{fileuploadmsg.label_boton}"
invalidFileMessage="#{fileuploadmsg.tipo_incorrecto}"
validator="fileLimitValidator">
<f:attribute name="fileLimit" value="#{fileLimit}"/>
<f:attribute name="size" value="#{listaDocumentos.size}"/>
</p:fileUpload>
and:
<p:fileUpload id="#{id}FileUpload"
fileUploadListener="#{bean[metodoTratarFichero]}" mode="advanced"
multiple="true" allowTypes="#{allowTypes}" showButtons="false"
update="#{id}ListaDocs #{id}MsgError" auto="true"
label="#{fileuploadmsg.label_boton}"
invalidFileMessage="#{fileuploadmsg.tipo_incorrecto}"
validator="#{fileLimitValidator}">
<f:attribute name="fileLimit" value="#{fileLimit}"/>
<f:attribute name="size" value="#{listaDocumentos.size}"/>
</p:fileUpload>
and:
<p:fileUpload id="#{id}FileUpload"
fileUploadListener="#{bean[metodoTratarFichero]}" mode="advanced"
multiple="true" allowTypes="#{allowTypes}" showButtons="false"
update="#{id}ListaDocs #{id}MsgError" auto="true"
label="#{fileuploadmsg.label_boton}"
invalidFileMessage="#{fileuploadmsg.tipo_incorrecto}"
validator="#{fileLimitValidator.validate}">
<f:attribute name="fileLimit" value="#{fileLimit}"/>
<f:attribute name="size" value="#{listaDocumentos.size}"/>
</p:fileUpload>
but the validate method is never called. What is the correct way to do it?
According to the FileUpload and FileUploadRenderer source code, the validator is only invoked when mode="simple" is been used (note: this in turn requires ajax="false" on command). The advanced mode will namely not set the uploaded file as component's submitted value, causing it to remain null until the listener method is invoked. As long as the submitted value is null, the validators are not invoked.
I'm not sure if this is intentional. Theoretically, it should be possible to set UploadedFile as submitted value and have the validator to rely on it. You might want to create an enhancement report at PrimeFaces issue tracker.
In the meanwhile, in spite of it being a poor practice, your best bet is really performing the validation in fileUploadListener method. You can just trigger validation failure add faces messages through the FacesContext like follows:
if (fail) {
context.validationFailed();
context.addMessage(event.getComponent().getClientId(context), new FacesMessage(
FacesMessage.SEVERITY_ERROR, messageSummary, messageDetail));
}
Otherwise, you'd need to create a custom renderer for the <p:fileUpload> which sets the submitted value during the decode() (I however don't guarantee that it would work in practice, you'll maybe stumble upon a peculiar problem which may turn out to be the reason why PrimeFaces didn't initially implement it like that).
By the way, your first and second validator attempt are correct. The third attempt works only if you used #ManagedBean instead of #FacesValidator (which is often done when injection of an #EJB is mandatory — which isn't possible in a #FacesValidator). The fourth attempt is invalid.
For validating a required primefaces file upload in mode advanced (ajax) it is possible to use this:
<f:metadata>
<f:event listener="#{bean.processValidations()}" type="postValidate" />
</f:metadata>
Where the implementation of the bean.processValidations() method would be something along the lines of:
public void processValidations() {
FacesContext context = FacesContext.getCurrentInstance();
UIInput fileUploadComponent = fileUploadsBean.getFileUploadComponent();
if (fileUploadComponent!=null && !isFileUploaded()) {
fileUploadComponent.setValid(false);
context.addMessage(fileUploadComponent.getClientId(context), new FacesMessage(FacesMessage.SEVERITY_ERROR, messageSummary, messageDetail));
context.validationFailed();
}
}
Where fileUploadsBean would be a REQUEST scoped CDI bean (won't work with standard JSF ManagedBeans) which you inject to your bean which has the processValidations() method defined, the method fileUploadsBean.getFileUploadComponent() returns the primefaces file upload component (you will use <p:fileUpload binding="#{fileUploadsBean.fileUploadComponent}" ...> for that). The method isFileUploaded() will determine if the file has been uploaded or not (probably just a null check on a member variable which you fill from fileUploadListener).
If you want to highlight the file upload button you can of course conditionally add a styleClass which you can then use for adding a red border for example.
styleClass="#{fileUploadsBean.fileUploadComponent.valid ? '' : 'validationFailed'}"
As a result the validation failed message for the primefaces file upload will be displayed along with all other jsf validation messages. You might have problem with maintaining order of the validation messages (will be always at the end), but it still beats displaying the failed upload file validation after user dealt with all the standard jsf validation messages from different fields and your action in a backing bean has been finally reached.

progressbar-primefaces3.5 with two different managed beans

Hi I have a xhtml (html1), which has a save button. The click of this renders method1 of Managedbean1. This method1, inturn called method2 of ManagedBean2 and on success, brings up html1. Is there a way to have a progressbar in html1 and see though both the managedbean actions and display till html2 comes up. So far, all the examples i see have one ui and one managedbean.
#mareckmareck - Thanks for your reply. This is what I am trying to do. - Please see the code excerpts.
regbudget.xhtml
<div id="actionButtonBarNew">
<p:panel styleClass="buttonPanelNew" >
<p:commandButton id="saveBudget" value="Save Budget" type="button" onclick="pbAjax.start();startButton1.disable();" widgetVar="startButton1" />
<p:progressBar widgetVar="pbAjax" value="#{regbudgetMgmtMB.handleBudgetEvent}" ajax="true" labelTemplate="{value}%">
<p:ajax event="complete" listener="#{progressBean.onComplete}"
update="growl" oncomplete="startButton1.enable()" render="#form" update="messages,fcotcol" /> />
</p:progressBar>
</p:panel>
</div>
=======================
RegbudgetBean (//regbudgetMgmtMB)
------------------------------
public void handleBudgetEvent(AjaxBehaviorEvent evt){
// more codee--- code here --
try {
HourAllocationManagedBean hbean = getCurrentInstanceOfHourAlloc();
hbean.calculateHourAlloc();
}
===============================
HourAllocationManagedBean
public void calculateHourAlloc() {
if(logger.isDebugEnabled()){
logger.debug("HourAllocationManagedBean: calculateHourAlloc");
}
//more code here---
try{
FacesContext.getCurrentInstance().getExternalContext().redirect("/pages/budget/hourAlloc.xhtml");
}
====================================================
As you can see, i am in regbudget.xhtml, call handleBudgetEvent in RegbudgetBean , which inturn calls calculateHourAlloc in HourAllocationManagedBean and displays hourAlloc.xhtml. My requirement is to have the progressbar in regbudget.xhtml to show progress till the houralloc.xhtml is displayed. Could you please let me know if you have any suggestions. Thanks.

Scroll p:messages into view when it is updated and (error) messages are present

I am working with PrimeFaces messages, I want my whole page to scroll to top when p:messages is rendered.
Assign an ID to your p:message component
<p:messages autoUpdate="true" id="myMessage" />
Then, in your backing bean call RequestContext.scrollTo method:
in PrimeFaces >= 6.0:
PrimeFaces.current().scrollTo("myMessage")
in Primefaces < 6.0:
RequestContext context = RequestContext.getCurrentInstance();
context.scrollTo("myMessage");
which is deprecated in PrimeFaces 6.0
Deprecated with PrimeFaces < 6.2
In you backing bean (that one which produces the messages), you should know when you render a p:message. If so simply execute this:
RequestContext.getCurrentInstance().execute("window.scrollTo(0,0);");
Update:
With the newer PrimeFaces versions (>= 6.2), the approach to execute Javascript on the client side is (by using x and y coordinates):
PrimeFaces instance = PrimeFaces.current();
instance.execute("window.scrollTo(0,0);");
To scroll to an element use the element's clientId:
PrimeFaces instance = PrimeFaces.current();
instance.scrollTo("myElementsClientId");
Find more information here:
http://de.selfhtml.org/javascript/objekte/window.htm#scroll_to
examples with jQuery for smooth scrolling as well: Scroll to the top of the page using JavaScript/jQuery?
Lets say that your button is causing the messages to appear.
XHTML
<p:commandButton value="Save"
oncomplete="scrollToFirstMessage()" />
javascript
//javascript function which scroll to the first message in page
function scrollToFirstMessage() {
try {
PrimeFaces.scrollTo($('.ui-message :first-child').eq(0).parent().attr('id'));
} catch(err) {
//No Message was found!
}
}
Hope this helps.
There are valid answers already that show how to scroll to the p:messages component, but they all require you to execute code in a backing bean. This requires you to do / call the same in each action. None show how to scroll to the messages component when it is rendered (updated).
You can implement a phase listener and check messages are present and if the messages component's clientId is present in the PartialViewContext renderIds:
These client identifiers are used to identify components that will be processed during the render phase of the request processing lifecycle.
Your listener can look something like this:
public class MessagesUpdateListener implements PhaseListener {
private final String MESSAGES_ID = "yourMessagesClientId";
#Override
public void afterPhase(PhaseEvent event) {
// Empty
}
#Override
public void beforePhase(PhaseEvent event) {
FacesContext fc = FacesContext.getCurrentInstance();
if (!fc.getMessageList().isEmpty() &&
fc.getPartialViewContext().getRenderIds().contains(MESSAGES_ID)) {
RequestContext.getCurrentInstance().scrollTo(MESSAGES_ID);
}
}
#Override
public PhaseId getPhaseId() {
return PhaseId.RENDER_RESPONSE;
}
}
Make sure to register it in your faces-config.xml:
<lifecycle>
<phase-listener>your.MessagesUpdateListener</phase-listener>
</lifecycle>
Tested with XHTML:
<h:form id="main">
<p:messages id="messages" />
<p:inputText id="text1" required="true" />
this<br/>is<br/>a<br/>long<br/>page<br/>this<br/>is<br/>a<br/>long<br/>page<br/>
this<br/>is<br/>a<br/>long<br/>page<br/>this<br/>is<br/>a<br/>long<br/>page<br/>
this<br/>is<br/>a<br/>long<br/>page<br/>this<br/>is<br/>a<br/>long<br/>page<br/>
this<br/>is<br/>a<br/>long<br/>page<br/>this<br/>is<br/>a<br/>long<br/>page<br/>
this<br/>is<br/>a<br/>long<br/>page<br/>this<br/>is<br/>a<br/>long<br/>page<br/>
this<br/>is<br/>a<br/>long<br/>page<br/>this<br/>is<br/>a<br/>long<br/>page<br/>
this<br/>is<br/>a<br/>long<br/>page<br/>this<br/>is<br/>a<br/>long<br/>page<br/>
<p:commandButton value="Update" update="messages text1"/>
<p:commandButton value="No update"/>
</h:form>
To check for global messages, use:
fc.getMessageList(null).isEmpty()
See also:
Add global message when field validation fails

is possible use two growls in one page

I want to use two growls in one page. One use to show success message that do auto hide (sticky="false"), the other one use to show failed messages that do not auto hide (sticky="true"):
<p:growl id="globalSuccessMessageGrowl" showDetail="false"
showSummary="true" life="3000" />
<p:growl id="globalFailedMessageGrowl" showDetail="false"
showSummary="true" sticky="true" />
public static void globalSuccessMessage(String message,
FacesMessage.Severity severity) {
FacesContext.getCurrentInstance().getViewRoot().findComponent("globalSuccessMessageGrowl");
renderComponent(new FacesMessage(severity, message, message), null,
"globalSuccessMessageGrowl");
}
public static void globalFailedMessage(String message,
FacesMessage.Severity severity) {
renderComponent(new FacesMessage(severity, message, message), null,
"globalFailedMessageGrowl");
}
...but the two growls do not auto hide after 3 seconds. Failed growl effects success growls?
You can assign different severity levels to each one. This was an attribute added to primefaces in version 3.3.
Check this question . The user had the same problem as you do.

CommandLink within PrimeFaces Mobile DataList is not referencing the correct element after being filtered

I'm working on a PrimFaces mobile employee directory app and have hit a road block. Its a simple app which consists of two screens (employee filter/list + employee detail).
I was able to load a datalist without issues. Clicking on the commandlink properly loads the employee detail. I then was able to implement a custom employee filter which was somewhat painful, but I got that working. The filter works by repopulating the employee datalist's model with the filtered results.
The issue is, after I use the filter to repopulate/filter the datalist, clicking on an employee (commandlink) does not pass the correct employee ID back to the model. Instead, the employee ID that was there before the filter was performed is passed. It's like the JSF model is not matching the DOM.
I'm using:
TomEE (MyFaces 2.1.7)
PrimeFaces Mobile 0.9.3
PrimeFaces 3.3
Both of my backing models are #ViewScoped
<pm:view id="peopleDirView" onload="">
<pm:header title="People Directory" fixed="true">
</pm:header>
<pm:content>
<h:form id="form">
<div data-role="fieldcontain">
<fieldset data-role="controlgroup">
<p:inputText id="searchCriteria" value="#{peopleDirectoryBean.criteria}" type="search"
onkeyup="delay(function() {filterResults();}, 500);" />
</fieldset>
</div>
<p:dataList id="peopleDataList" value="#{peopleDirectoryBean.people}" var="person" rowIndexVar="rowIndex">
<p:column>
<p:commandLink action="#{peopleDirectoryDetailBean.loadPersonDetail(person.employeeId)}" update=":personDetailView">
<img src="/phonedir/people/image/#{person.employeeId}?width=75&height=100" width="90" height="100"
onerror="missingImage(this);" id="per-search-picture" />
<h1>#{person.nameLast}, #{person.nameFirst}</h1>
<p>#{person.deptName}</p>
<p>#{person.jobTitle}</p>
</p:commandLink>
</p:column>
</p:dataList>
<p:remoteCommand name="filterResults" update="peopleDataList" action="#{peopleDirectoryBean.peopleSearch}" />
</h:form>
</pm:content>
<pm:footer fixed="true">
<pm:navBar>
<p:button value="People" icon="home" href="#peopleDirView?reverse=true" styleClass="ui-btn-active" />
<p:button value="Locations" icon="info" href="#locationsView?reverse=true" />
<p:button value="Conference" icon="search" href="#conferenceRoomsView?reverse=true" />
</pm:navBar>
</pm:footer>
<script>
var delay = (function() {
var timer = 0;
return function(callback, ms) {
clearTimeout(timer);
timer = setTimeout(callback, ms);
};
})();
function missingImage(image) {
image.onerror = "";
image.src = "missing-person.jpg";
return true;
}
</script>
</pm:view>
Okay, looks like the mistake was on my part.
In my backing bean, I was using javax.inject.Named (#Named) because I was trying to make use of my container's ability to do CDI. Once I changed it to javax.faces.bean.ManagedBean (#ManagedBean ) the problem went away. The TomEE docs state that it supports #Named so I'm not sure what the deal is.