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

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

Related

PrimeFaces confirmdialogs from single Bean

Submit button is pressed the bean first checks for valid values, if it fails validation a dialog is presented. While the process is running another session submits a button press and the bean checks the flag and need to present a different dialog.
Is there away to have a single commandButton interact with two
different confirmDialogs, commandButton "update" interacts with the
confirmDialog
The main difference with my issue verse the other examples/solutions, there is only one button. And the update="confirmValid" on the submit button is only working for the first button push.
The bean is called successfully from "second" button press, the forceRequest method doesn't display the dialog
<p:commandButton id="myButton" update="confirmValid growl"
value="Submit"
actionlistener="#{message.sendMessage}"
...
/>
This dialog is presented for display when the request is invalid
<p:confirmDialog header="#{message.invalidValuesHdr}"
id="confirmValidData" message="#{message.invalid}"
wigdetVar="confirmValidData">
<p:commandButton value="Ok" update="growl" oncomplete="PF('confirmValidData').hide()"
</p:confirmDialog>
This dialog is presented when the process flag has been updated
<p:confirmDialog header="#{message.forceRequestHdr}"
id="confirmValidData" message="#{message.invalid}"
wigdetVar="confirmForce">
<p:commandButton value="Ok" update="growl" oncomplete="PF('confirmForce').hide()"
</p:confirmDialog>
Bean:
#ViewScoped
#Override
public void sendMessage() {
if (....)
forceRequest();
}
public void forceRequest(){
FacesMessage message = new
FacesMessage(FacesMessage.SEVERITY_INFO,"Message Title", "Message body");
RequestContext.getCurrentInstance().showMessageInDialog(message);
}
Displays a dialog the method below does nothing, which is the issue
public void forceRequest(){
RequestContext context = RequestContext.getCurrentInstance();
context.openDialog("Confirm");
context.execute("PF('confirmForce').jq.click();");
}
faces-config.xml is updated
public void forceRequest(){
RequestContext.getCurrentInstance().execute("PF('confirmForce').show();");
}
Above was the solution and now on to the bean

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.

Pass a bean in a dialog with Dialog Framework in Primefaces

I have some problem to pass a entire bean in a dialog.
I would like to open a dialog with Dialog Framework in Primefaces, and pass the method and attributes content in bean.
I tried to make this code, but it don't work.How should I do?
<p:commandButton value="open dialog" ajax="true"
actionListener="#{processController.openSelectFieldDialog}"
update="tableResult , :notificationForm:info-messages">
<f:attribute name="controller" value="#{processController}" />
</p:commandButton>
This is the code inside openSelectFieldDialog method:
public void openSelectFieldDialog(){
RequestContext.getCurrentInstance().openDialog("genericSelectFieldDialog");
}
And this is the code inside the dialog controller:
public void onload() {
Object somethingBean= FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("controller");
}
I understand that i pass parameters on openDialog method, but i don't find any example on primefaces site. Can you help me?
Thanks

PrimeFaces open dialog several times with rendered attribute

I try to implement a dialog box accessible everywhere in my project and I was wondering if this solution is possible.
The dialog is included in the template of my project. For example, where I am on the login page, I would like to show the dialog when the button "Login" is clicked and the authentication is successful. So I catch the bean linked to the dialog with:
getFacesContext().getELContext().getELResolver().getValue(getFacesContext().getELContext(), null, beanName);
and I set the "show" argument. (have a look below)
The first time, it's working. When I access the login page, the dialog is not rendered and when I click the button login, the attribute show is set, the page is updated and the dialog appears. But if I close it, I could not fire it again when I click again the button. (The dialog is rendered but not shown)
My dialog is like this (I have visible="true" cause I want to show each time it's rendered):
<h:form>
<p:dialog header="Dialog" widgetVar="myDialog" rendered="#{bean.show}" visible="true">
<p:ajax event="close" listener="#{bean.onClose}" />
...
</p:dialog>
</h:form>
The bean is in viewscope:
#ManagedBean(name = "bean")
#ViewScoped
public class MyBean {
private boolean show; // + Getters and Setters
#PostConstruct
public void init() {
this.show = false;
...
}
public void onClose() {
this.show = false;
}
}
And I can add that my LoginBean which is setting the show argument is in viewScope too.
Thanks

java.awt.HeadlessException when calling JOptionPane.showMessageDialog in backing bean action method

I'm trying the following:
labelconfig.xhtml:
<h:form id="ok">
<h:commandButton value="click">
<f:ajax event="click" listener="#{canvasController.oeps}" />
</h:commandButton>
</h:form>
And I'm trying to get it here:
CanvasController.java
#ManagedBean(name = "canvasController")
#SessionScoped
public class CanvasController
public void oeps(AjaxBehaviorEvent event) {
JOptionPane.showMessageDialog(null, "SUCCES3");
}
}
But when I click the button, I get:
serverError: class java.awt.HeadlessException
How is this caused and how can I solve it?
You are trying to call Swing from server application without any desktop GUI. Instead of JOptionPane use logger or FacesContext.addMessage to get feedback. If for some reason you do want to control Swing app through JSF make sure DISPLAY etc are set but then I suggest rephrasing your question.