5

I am working with PrimeFaces messages, I want my whole page to scroll to top when p:messages is rendered.

Jasper de Vries
  • 19,370
  • 6
  • 64
  • 102
Ami
  • 53
  • 1
  • 1
  • 3

4 Answers4

7

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

Kalle Richter
  • 8,008
  • 26
  • 77
  • 177
Jorge Marmolejo
  • 574
  • 6
  • 17
6

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:

Manuel
  • 3,828
  • 6
  • 33
  • 48
  • RequestContext.getCurrentInstance().execute("window.scrollTo(0,0);"); is deprecated. Use PrimeFaces.current().executeScript("window.scrollTo(0,0);"); instead. – Alexandre Alves Oct 17 '18 at 13:19
  • Thanks for the info, but your script is only partially correct. See my updated answer. – Manuel Oct 17 '18 at 19:59
1

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.

Hatem Alimam
  • 9,968
  • 4
  • 44
  • 56
  • 1
    Javascript could also look like this: `$('.ui-messages :first-child').eq(0).parent()[0].scrollIntoView();` Just JS + jQuery. – ARK Apr 21 '16 at 06:49
  • I'm not a jQuery expert. Could you explain what the query, `eq(0).parent.attr('id')` stands for in details, please (ideally not in a comment, but in the answer)? – Kalle Richter May 30 '18 at 21:13
1

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:

Jasper de Vries
  • 19,370
  • 6
  • 64
  • 102
  • 1
    Creative... had me thinking... You could also add a passtrough attribute to the `p:messages` like `scrollToWhenDisplayed` and override a small part of the PrimeFaces messages component and in it check for the presence of the scrollToWhenDisplayed and if present scroll to it. No need for a phaselistener then and no need to know the id of the component in it... – Kukeltje Mar 04 '18 at 19:54