Morten Holmgaard
Morten Holmgaard

Reputation: 7796

JSF 2.1 preRenderEvent not working on GET request

I can't get the preRenderView event listener to work on a GET request in JSF 2.1.

I have found a lot about it but nothing seems to work e.g.:
Conditional redirection in JSF
http://andyschwartz.wordpress.com/2009/07/31/whats-new-in-jsf-2/#get-prerenderview-event
http://developer.am/j2eetutorial/jsf/?page=jsf-2-prerenderviewevent-example
JSF, Spring, and the PreRenderViewEvent
http://balusc.blogspot.dk/2011/09/communication-in-jsf-20.html#ProcessingGETRequestParameters

I have a template with 4 insert blocks and I have tried to insert the event code at all those places but without any luck. I have tried both with and without the f:metadata tag surrounding it.

<f:event type="preRenderView" listener="#{applicationData.redirectIfNoResults}" />

Bean:

@ManagedBean
@ApplicationScoped
public class ApplicationData implements Serializable {
    public void redirectIfNoResults() throws IOException { 
        if (getTotal() < 1) { 
            ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext(); 
            ec.redirect(ec.getRequestContextPath() + "/noResults.xhtml"); 
        } 
    } 
    ...
}

Template:

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:f="http://java.sun.com/jsf/core">
    <ui:insert name="beforeHeader" />
    <f:view>
        <ui:insert name="inView" />
    </f:view>
    <h:head>
        <meta http-equiv="cache-control" content="no-store" />
        <link href="style.css" rel="stylesheet" type="text/css" />
        <title>Quick Poll</title>
        <ui:insert name="header" />
    </h:head>
    <h:body>
        <h1>Quick Poll</h1>
        <ui:insert name="content" />
    </h:body>
</html>

View:

    <ui:define name="content">
        #{applicationData.question}?<p/>
        <h:panelGrid columns="3" border="0">
                Yes: 
                <h:panelGrid bgcolor="black" height="20" width="#{300*applicationData.yes/applicationData.total}"/>
                #{applicationData.yes}
                <h:outputText value="No:"/> 
                <h:panelGrid bgcolor="black" height="20" width="#{300*applicationData.no/applicationData.total}"/>
                #{applicationData.no}
        </h:panelGrid>
    </ui:define>
</ui:composition>

Please help me figure out how to get it working..

Update 1:
I have made changes as suggested by BalusC but it is still not working..

Template:

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:f="http://java.sun.com/jsf/core">
    <h:head>
        <meta http-equiv="cache-control" content="no-store" />
        <link href="style.css" rel="stylesheet" type="text/css" />
        <title>Quick Poll</title>
        <ui:insert name="header" />
    </h:head>
    <h:body>
        <h1>Quick Poll</h1>
        <ui:insert name="content" />
    </h:body>
</html>

View:

<?xml version='1.0' encoding='UTF-8' ?>
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
    xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:c="http://java.sun.com/jsp/jstl/core"
    xmlns:f="http://java.sun.com/jsf/core"
     template="template.xhtml">
    <ui:define name="content">
        <f:event listener="#{applicationData.redirectIfNoResults}" type="preRenderView"></f:event> 
        #{applicationData.question}?<p/>
        <h:panelGrid columns="3" border="0">
                Yes: 
                <h:panelGrid bgcolor="black" height="20" width="#{300*applicationData.yes/applicationData.total}"/>
                #{applicationData.yes}
                <h:outputText value="No:"/> 
                <h:panelGrid bgcolor="black" height="20" width="#{300*applicationData.no/applicationData.total}"/>
                #{applicationData.no}
        </h:panelGrid>
    </ui:define>
</ui:composition>

Upvotes: 0

Views: 1458

Answers (3)

Morten Holmgaard
Morten Holmgaard

Reputation: 7796

I ended up making a solution with a PostConstruct method in a view scope bean.
Like this: Initializng a Backing Bean With Parameters on Page Load with JSF 2.0

Bean:

@ManagedBean 
@ViewScoped
public class ResultsController {
    @ManagedProperty(value="#{applicationData.total}")  
    private int total; 
    @ManagedProperty(value="#{applicationData.yes}")  
    private int yes; 
    @ManagedProperty(value="#{applicationData.no}")  
    private int no; 

    @PostConstruct 
    public void postConstruct() {
        if (getTotal() < 1) { 
            ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext(); 
            try {
                ec.redirect(ec.getRequestContextPath() + "/noResults.jsf");
            } catch (IOException e) {
                System.out.println("noResults.jsf redirect failed.");
                e.printStackTrace();
            } 
        } 
    }
    ...
}

View:

<?xml version='1.0' encoding='UTF-8' ?>
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
    xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:c="http://java.sun.com/jsp/jstl/core"
    xmlns:f="http://java.sun.com/jsf/core"
     template="template.xhtml">
    <ui:define name="content">
        #{applicationData.question}?<p/>
        <h:panelGrid columns="3" border="0">
                Yes: 
                <h:panelGrid bgcolor="black" height="20" width="#{300*resultsController.yes/resultsController.total}"/>
                #{resultsController.yes}
                <h:outputText value="No:"/> 
                <h:panelGrid bgcolor="black" height="20" width="#{300*resultsController.no/resultsController.total}"/>
                #{resultsController.no}
        </h:panelGrid>
    </ui:define>
</ui:composition>

Upvotes: 0

BalusC
BalusC

Reputation: 1108632

That <f:view> isn't rightly used, it has to wrap the entire view. Remove it (JSF will implicitly create one), or at least let it wrap the entire view, including <h:head> and <h:body> tags.

By the way, the <f:event> does not need to go in a <f:metadata>. That applies only to <f:viewParam>. A <f:event> listener which depends on results of <f:viewParam> is indeed often for sole self-documentary purposes also placed in the same <f:metadata> block, but that is thus not a requirement of <f:event> itself.

In your case, it'd be easier to just put it in <ui:define name="content">.

Upvotes: 2

Karl Kild&#233;n
Karl Kild&#233;n

Reputation: 2435

ComponentSystemEvent seems to be missing in the method signature.

Method needs to look like this:

public void newRequest(final ComponentSystemEvent event) {
System.out.println("Someone requested me");
}

And then place a caller in the template or in the seperate views, that won't do any difference.

<f:event listener="#{userSessionAction.newRequest}" type="preRenderView"></f:event>

Upvotes: 0

Related Questions