there's a jsf page with a form:
....
<h:form>
<h:commandLink action="#{userBean.logout}" value="Logout" />
</h:form>
....
<ui:repeat value="#{categoryBean.allCategories}" var="c">
....
The categoryBean.allCategories is a call to EJB which is based on a <f:param> from previous page acquired via #ManagedProperty. So when the user clicks on Logout, the whole page evaluates, but without the param and there's NullPointerException. Is there any possibility how to skip the evaluation?
Make use of the rendered attribute:
<h:panelGroup rendered="#{not empty param.name}">
<ui:repeat value="#{categoryBean.allCategories}" var="c">
...
</ui:repeat>
</h:panelGroup>
Alternatively you can also just do a nullcheck in getAllCategories() method.
if (param != null) {
// Return it.
}
return null;
Related
I am using Java EJB with JSF.
What I doing is just a simple search result from database and display it on a table using JSF with ajax. But why when first submitting, the result is not appear. And second time only the result will appear.
Below is my JSF page code
<h:form id="wholeForm">
<p:panelGrid id="resultTable" styleClass="result_table1" >
<p:row>
<p:column>
<div align="center" id="font-size1">
<h:selectOneRadio value="#{scanResult.typeOfScan}">
<f:selectItem itemValue="Carrier" itemLabel="Carrier"></f:selectItem>
<f:selectItem itemValue="Slot" itemLabel="Slot"></f:selectItem>
<f:selectItem itemValue="HD" itemLabel="HD"></f:selectItem>
<p:ajax event="change"></p:ajax>
</h:selectOneRadio>
Scan: <p:inputText styleClass="searchField" id="counter" value="#{scanResult.serialNumber}" a:autofocus="true">
<p:ajax event="keydown" update="wholeForm" onstart="if (event.keyCode != 13) { return false;}" listener="#{scanResult.checkResult()}" />
</p:inputText>
<br/><br/>
</div>
</p:column>
</p:row>
</p:panelGrid>
<p:panelGrid id="resultTable1" styleClass="result_table1" rendered="#{not empty scanResult.scanResultCarrier}" >
<c:forEach items="#{scanResult.scanResultCarrier}" var="result" >
<!-- ..do something and call out result -->
</p:column>
</p:row>
</c:forEach>
</p:panelGrid>
</h:form>
And my managed bean is as below
#Named(value = "scanResult")
#SessionScoped
public class scanResult implements Serializable {
//Some code here
public void checkResult() {
scanResultCarrier = new ArrayList<>();
scanResultSlot = new ArrayList<>();
System.out.println("checking");
if (typeOfScan.equals("Carrier")) {
System.out.println("Serial " + serialNumber);
scanResultCarrier = scanresultcarrierFacade.searchResultCarrier(serialNumber);
System.out.println(scanResultCarrier.size());
} else if (typeOfScan.equals("Slot")) {
scanResultSlot = scanresultslotFacade.searchResultSlot(serialNumber);
} else if (typeOfScan.equals("HD")) {
} else {
}
serialNumber = "";
}
}
I use System.out.println(lsitofresult.size()); to print out my result and the result is not blank. Mean that I successful retrieve my result from database.
But my result table not able to show out after I click on enter.
Then I notice that my url is as below
http://localhost:8080/outgoingScanSystem-war/faces/index.xhtml;jsessionid=8b6cefa932ff60984607ee38ec13
And after I refresh my page, the result will appear again.
And my url change to :
http://localhost:8080/outgoingScanSystem-war/faces/index.xhtml
May I know why? Is it related to URL? I have no idea where should I start my troubleshoot. Anyone can give me some guideline?
I see some problems here. First of all, you're using the session scope while your managed bean should be view scoped (there's no reason to use the session here, see the link below). That's the cause why your results are getting displayed when you refresh the page.
Second, I'd rather put the search results out from the form. I see no reason for them to be in the same form of the search itself. Then, when performing a searh you should only update the result list:
<p:ajax event="keydown" update="resultTable1" onstart="if (event.keyCode != 13) { return false;}" listener="#{scanResult.checkResult()}" />
Third, as you're using Primefaces, I encourage you to take a look to its p:remoteCommand tool in order to perform ajax-based calls to the beans from your JS code directly. This way you should avoid your second problem, which seems to be that you're preventing the standard form sending on the ajax start event (which might not even get called). You could do something like this:
<p:remoteCommand name="search" update="resultTable1" actionListener="#{scanResult.checkResult}" />
<p:inputText styleClass="searchField" id="counter" value="#{scanResult.serialNumber}"
a:autofocus="true" onkeypress="if (event.keyCode != 13) {search(); return false;}">
<!-- Update the input text value in the bean for each pressed key -->
<p:ajax event="keydown" />
</p:inputText>
See also:
How to choose the right bean scope?
Jsf calling bean method from input text when pressing enter
myBean is in request scope.
<h:form id="indexFormID">
<a4j:outputPanel ajaxRendered="true" layout="block">
<h:inputText id="inputForHD" value="#{myBean.inputParam}"></h:inputText>
<a4j:commandLink value="Submit" action="#{myBean.myMethod}" reRender="renderSuccess" process="indexFormID:inputForHD"></a4j:commandLink>
</a4j:outputPanel>
<h:panelGroup id="renderSuccess">
<h:panelGroup rendered="#{myBean.someBoolean}">
//Some other JSF components go here
</h:panelGroup>
</h:panelGroup>
</h:form>
MyBean class definition:
private String inputParam;
//Getters and setters are there
public String myMethod()
{
log.debug("~ Value of inputParam" +this.getInputParam()); //This is printing null value for inputParam
//when commandLink is clicked
return null;
}
Why my inputParam is not getting set with the input parameters?
Ok I found few issues with your approach:
<h:inputText id="inputForHD" value="#{myBean.inputParam}"></h:inputText>
You are already mapping the inputParam attribute with this bean, why have a new Id "inputForHD"
Use the inputParam itself, if you want to use inputForHD, you can pick the same from request Parameter map like.
String inputForHD = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("indexFormID:inputForHD");
Also as I mentioned previously wrap the output panel inside the and a4j panel e.g.
<h:panelGroup id="renderSuccess">
<h:panelGroup rendered="#{helloWorld.someBoolean}">
//Some other JSF components go here
<h:inputText id="inputForHDasdasd" value="#{helloWorld.inputParam}"></h:inputText>
</h:panelGroup>
</h:panelGroup>
This is working fine, let know if any issues.
I've been using JSF for a while but there's something that has always confused me. Hopefully someone can help.
Simple example, there's a page that shows a table of "Person"s and when you click on the "Person" name, it takes you to a page to view the details of the "Person".
Typically, I implement a personSearch.jsf page like this:
<h:dataTable value="#{personHandler.persons}" var="person">
<h:column>
<h:commandLink action="#{personHandler.show( person.id )}" >
<h:outputText value="#{person.name}" />
</h:commandLink>
</h:column>
</h:dataTable>
And I implement a personView.jsf page like this:
<h:panelGrid columns="2">
<h:outputText value="Person ID:" />
<h:outputText value="#{personHandler.selectedPerson.id}" />
<h:outputText value="Person Name:" />
<h:outputText value="#{personHandler.selectedPerson.name}" />
</h:panelGrid>
PersonHandler.show(Integer personId) sets personHandler.selectedPerson and then redirects to the personView page.
This all works fine when PersonHandler is a session bean. But I prefer it to be a request scoped bean because the user may have several windows open and I don't want there to be only one selected person per session.
So my question is, what's the "correct" way to do this JSF? I was once able to get what I wanted using a4j:keepAlive on the personHandler, but that always felt like a kludge. Again, this is something I've never understood about JSF.
Any help is greatly appreciated!
rob
If the view is supposed to be bookmarkable, pass the person ID as a GET request parameter instead of a POST request "parameter".
<h:outputLink value="viewperson.xhtml">
<f:param name="id" value="#{person.id}" />
</h:outputLink>
This way you can use two #RequestScoped beans, one for the list and one for the view. You can preload the selected person as follows:
#ManagedProperty(value="#{param.id}")
private Long id;
#PostConstruct
public void init() {
selectedPerson = personDAO.find(id);
}
If it is not supposed to be bookmarkable, then just create a single view which renders the view state conditionally.
<ui:fragment rendered="#{!personHandler.viewMode}">
<h:form>
<h:dataTable value="#{personHandler.persons}" var="person">
<h:column>
<h:commandLink value="#{person.name}" action="#{personHandler.show(person)}" />
</h:column>
</h:dataTable>
</h:form>
</ui:fragment>
<ui:fragment rendered="#{personHandler.viewMode}">
<h:form>
...
<h:commandLink value="Go back" action="#{personHandler.back}" />
</h:form>
</ui:fragment>
(You can if necessary split out the content of the both framgents to another Facelet files which you include by <ui:include>)
This way you can use a single #ViewScoped bean with action methods returning void or null.
public void show(Person selectedPerson) {
this.selectedPerson = selectedPerson;
}
public void back() {
selectedPerson = null;
}
public boolean isViewMode() {
return selectedPerson != null;
}
You can even wrap the whole view in some
<h:panelGroup id="container">
and nest the following in both command links to let Ajax magic do the work
<f:ajax execute="#form" render=":container" />
I have the code bellow:
<c:set var="show" value="#{cartBean.itemsAdded}" />
<c:if test="${show}">
<h:form id="test1">
<h:commandLink action="#{cartBean.foo}">this doesn't work</h:commandLink>
</h:form>
</c:if>
<h:form id="test2">
<h:commandLink action="#{cartBean.foo}">this works!</h:commandLink>
</h:form>
When show=false, show only the second link.
And it works. I can reach server (I'm using debug to see this).
When show=true, both links appears. But ONLY second link works. The link inside conditional doesn't trigger the action in server.
Someone, can, please, help me?
Note: the same thing happens when I use a4j:outputPanel rendered="#{show}"
During processing of the form submit, JSF will re-evaluate whether the command button/link is been rendered. If it is not rendered, then it will simply skip the action.
You need to ensure that the expression #{cartBean.itemsAdded} returns true as well when the form submit is been processed by JSF. An easy test is to put the bean in the session scope (and I assume that the isItemsAdded() is a pure getter, i.e. it contains only return itemsAdded;).
If that did fix the problem and you'd like to keep the bean in the request scope, then add a <a4j:keepAlive> to retain the bean properties in the subsequent request.
<a4j:keepAlive beanName="#{cartBean}" />
See also:
Commandlink is not being invoked
Unrelated to the concrete problem, you should prefer JSF tags/attributes over JSTL ones as much as possible. In this particular case, you should get rid of both JSTL <c:> tags and use the JSF-provided rendered attribute instead:
<h:form id="test1" rendered="#{cartBean.itemsAdded}">
<h:commandLink action="#{cartBean.foo}">this doesn't work</h:commandLink>
</h:form>
WORKARROUND:
I don't want to use sessionScope, because of the danger of use this in a huge system (my case). I don't like to use keepAlive neighter, because I'm in a clutered server and many attributes are not serializable.
Anyway, I've found this workarround:
Send a parameter in request (like show=true)
Change the check method, adding a OR in return to see this new parameter.
MANAGED BEAN:
Before:
public boolean itemsAdded() {
return foo; // my initial check
}
After:
public HttpServletRequest getRequest() {
return (HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext().getRequest();
}
public boolean itemsAdded() {
return foo || getRequest().getParameter("show") != null;
}
XHTML:
Before:
<c:set var="show" value="#{cartBean.itemsAdded}" />
<c:if test="${show}">
<h:form id="test1">
<h:commandLink action="#{cartBean.foo}">link</h:commandLink>
</h:form>
</c:if>
After:
<c:set var="show" value="#{cartBean.itemsAdded}" />
<c:if test="${show}">
<h:form id="test1">
<h:commandLink action="#{cartBean.foo}">link
<f:param name="show" value="true"/>
</h:commandLink>
</h:form>
</c:if>
IMPROVED (and tiny) WORKARROUND:
Change only XHTML:
Before:
<c:if test="#{cartBean.itemsAdded}">
<h:form id="test1">
<h:commandLink action="#{cartBean.foo}">link</h:commandLink>
</h:form>
</c:if>
After:
<c:if test="#{cartBean.itemsAdded || params['show']}">
<h:form id="test1">
<h:commandLink action="#{cartBean.foo}">link
<f:param name="show" value="true"/>
</h:commandLink>
</h:form>
</c:if>
Related to a previous example, i tried to monitor my get/set methods on the server (when they are called, and how often). So, my actual been look such :
#ManagedBean(name="selector")
#RequestScoped
public class Selector {
#ManagedProperty(value="#{param.profilePage}")
private String profilePage;
public String getProfilePage() {
if(profilePage==null || profilePage.trim().isEmpty()) {
this.profilePage="main";
}
System.out.println("GET "+profilePage);
return profilePage;
}
public void setProfilePage(String profilePage) {
this.profilePage=profilePage;
System.out.println("SET "+profilePage);
}
}
and the only page who can call this method (it only calls the get method on rendered) is :
<!DOCTYPE html>
<ui:composition
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets">
<h:panelGroup layout="block" id="profileContent">
<h:panelGroup rendered="#{selector.profilePage=='main'}">
// nothing at the moment
</h:panelGroup>
</h:panelGroup>
</ui:composition>
my stupor when i see the server log, and i see :
SET null
GET main
GET main
GET main
GET main
GET main
GET main
GET main
What? It call seven times the getProfilePage() method? (and also 1 time setProfilePage())
I would like to know why this behaviour :)
Thanks
ADDED AN EXAMPLE
Bean
#ManagedBean(name="selector")
#RequestScoped
public class Selector {
#ManagedProperty(value="#{param.profilePage}")
private String profilePage;
#PostConstruct
public void init() {
if(profilePage==null || profilePage.trim().isEmpty()) {
this.profilePage="main";
}
}
public String getProfilePage() { return profilePage; }
public void setProfilePage(String profilePage) { this.profilePage=profilePage; }
}
profile.xhtml
<h:panelGroup layout="block" id="profileContent">
<h:panelGroup layout="block" styleClass="content_title">
Profilo Utente
</h:panelGroup>
<h:panelGroup rendered="#{selector.profilePage=='main'}">
<ui:include src="/profile/profile_main.xhtml" />
</h:panelGroup>
<h:panelGroup rendered="#{selector.profilePage=='edit'}">
<ui:include src="/profile/profile_edit.xhtml" />
</h:panelGroup>
</h:panelGroup>
// profile_main.xhtml
<h:form id="formProfileMain" prependId="false">
<h:panelGroup layout="block" styleClass="content_span">
<h:outputScript name="jsf.js" library="javax.faces" target="head" />
<h:panelGroup layout="block" styleClass="profilo_3">
<h:commandButton value="EDIT">
<f:setPropertyActionListener target="#{selector.profilePage}" value="edit" />
<f:ajax event="action" render=":profileContent"/>
</h:commandButton>
</h:panelGroup>
</h:panelGroup>
</h:form>
// profile_edit.xhtml
<h:form id="formProfileEdit" prependId="false">
<h:panelGroup layout="block" styleClass="content_span">
<h:outputScript name="jsf.js" library="javax.faces" target="head" />
<h:panelGroup layout="block" styleClass="profilo_3">
<h:commandButton value="Edit">
<f:setPropertyActionListener target="#{selector.profilePage}" value="editProfile" />
<f:ajax event="action" render=":profileContent"/>
</h:commandButton>
<h:commandButton value="Back">
<f:setPropertyActionListener target="#{selector.profilePage}" value="main" />
<f:ajax event="action" render=":profileContent"/>
</h:commandButton>
</h:panelGroup>
</h:panelGroup>
</h:form>
In this example, i call the profile_main (as default); After (for example) I call profile_edit (by clicking on EDIT); After, I return to profile_main by clicking Back. Now, if i want to reload profile_edit (EDIT), i need to click many times on that command button. Why?
EL (Expression Language, those #{} things) won't cache the result of the calls or so. It just accesses the data straight in the bean. This does normally not harm if the getter just returns the data.
The setter call is done by #ManagedProperty. It basically does the following:
selector.setProfilePage(request.getParameter("profilePage"));
The getter calls are all done by rendered="#{selector.profilePage == 'some'}" during the render response phase. When it evaluates false the first time, in UIComponent#encodeAll(), then no more calls will be done. When it evaluates true, then it will be re-evaluated six more times in the following sequence:
UIComponent#encodeBegin() - Locates renderer for the begin of component.
Renderer#encodeBegin() - Renders begin of component.
UIComponent#encodeChildren() - Locates renderer for children of component.
Renderer#encodeChildren() - Renders children of component.
UIComponent#encodeEnd() - Locates renderer for end of component.
Renderer#encodeEnd() - Renders end of component.
The component and its renderer verifies during every step if it is allowed to render. During a form submit, if an input or command component or any of its parents has a rendered attribute, then it will also be evaluated during apply request values phase as part of safeguard against tampered/hacked requests.
True, this look like clumsy and inefficient. It was considered the achilles heal of JSF as per spec issue 941. It's been suggested to remove all those repeated checks and stick to the one done in UIComponent#encodeAll(), or to evaluate isRendered() on a per-phase basis. During EG discussion, it became clear the root of the problem is in EL, not in JSF, and that performance could be greatly improved with CDI. So there was no necessity to solve it from JSF spec side on.
If your concern is that the managed property should be checked only once after its setting if it's null or empty, then consider to move it into a method which is annotated with #PostConstruct. Such a method will be called directly after bean's construction and all dependency injection.
#PostConstruct
public void init() {
if (profilePage == null || profilePage.trim().isEmpty()) {
profilePage = "main";
}
}
See also:
Why JSF calls getters multiple times?
you can use CDI Producers methods.
It will be called many times, but the result of first call is cached in scope of the bean and is efficient for getters that are computing or initializing heavy objects!
See here, for more info.