I want to do multiple actions on different managed beans with the same button, one being scoped session and the other request. In my example I use the same bean for both.
index.xhtml
<h:form>
<p:commandButton image="ui-icon ui-icon-notice" action="#{controller.inc()}" update="result">
<f:actionListener type="controller.Controller" />
</p:commandButton>
</h:form>
<p:panel id="result">
#{controller.count}
</p:panel>
controller.Controller.java
#Named(value = "controller")
#SessionScoped
public class Controller implements ActionListener, Serializable
{
int count = 0;
public Controller(){
System.out.println("new");
}
public void inc(){
count += 1;
}
public int getCount(){
return count;
}
#Override
public void processAction(ActionEvent event) throws AbortProcessingException{
count += 1000;
}
}
When I press the button the count increases by 1, instead of 1001, and creates a new bean. What did I do wrong ?
Thanks.
That's expected behaviour. The <f:actionListener type> creates and gets its own bean instance on every declaration. It does not reuse the same session scoped bean which is managed by JSF.
You need to use binding instead to bind to the already-created session scoped bean instance.
<f:actionListener binding="#{controller}" />
Related
I have the following menu items in index.xhtml
<p:menuitem ajax="false" value="A" action="#{bean.start('A')}" />
<p:menuitem ajax="false" value="B" action="#{bean.start('B')}" />
The following code on my backing bean doesn't work when the bean is ViewScoped (I don't want to make it SessionScoped):
#Named
#ViewScoped
public class Bean implements Serializable {
private LetterEnum letter;
public String findBSEmpty(String str) {
if (saison.equals("A")) {
this.letter = LetterEnum.A;
return "a.xhtml";
} else {
this.letter = LetterEnum.B;
return "b.xhtml";
}
}
public void doSomthing(){
//Method called from other a.xhtml and b.xhtml
//Processing data depending on the value of "letter"
}
I know that view scoped beans are recycled after every view change and I have must start from index.xhtml and depending on the choice of the user, the application will display a.xhtml or b.xhtml to continue processing other data.
Am I missing somthing?
What are the best practices about this kind of navigation?
BTW, I am using JSF 2.2 with Payara 4
I have a p:selectOneMenu in my application, and when the selection takes place I need to call multiple back-end methods from different managed beans in order to perform different actions.
XHTML code:
<p:selectOneMenu id="selectMenu" value="#{userBean.selectedSite}"
converter="siteConverter" style="width:150px">
<p:ajax event="change" listener="#{bean2.changeSite}"
render="#form :comp1 :comp2 :comp3 :comp4" />
<f:selectItems value="#{userBean.sites}" var="site"
itemValue="#{site}" itemLabel="#{site.description}" />
<p:ajax event="change" listener="#{bean1.reset}"
update="#form :comp1 :comp2 :comp3 :comp4" />
</p:selectOneMenu>
Managed bean 1:
#ManagedBean(name="bean1")
#ViewScoped
public class Bean1 implements Serializable {
// ...
public void reset() {
loadEvents();
resetEvent();
}
}
Managed bean 2:
#ManagedBean(name="bean2")
#SessionScoped
public class Bean2 implements Serializable {
// ...
public void changeSite() {
FacesContext context = FacesContext.getCurrentInstance();
Bean1 bean = (Bean1) context.getApplication().evaluateExpressionGet(context, "#{bean1}", Bean1.class);
reload();
bean.loadEvents();
}
}
If, instead of using two different p:ajax components, I use a single p:ajax that calls a single method from Bean1, the page components listed under "update" are not correctly updated.
XHTML:
<p:ajax event="change" listener="#{bean1.singleMethod}"
update="#form :comp1 :comp2 :comp3 :comp4" />
Managed bean 1:
#ManagedBean(name="bean1")
#ViewScoped
public class Bean1 implements Serializable {
// ...
public void () singleMethod() {
FacesContext context = FacesContext.getCurrentInstance();
Bean2 bean = (Bean2) context.getApplication().evaluateExpressionGet(context, "#{bean2}", Bean2.class);
bean2.changeSite();
reset();
}
}
Changing the selected values updates the server side objects, but the page is not updated: if I press F5, the page shows the actual situation.
Moving the single global method to the session scoped bean (Bean2) does the job.
I am very new to ajax and trying to copy the value of one box to another. Here is my code:
<h:form>
<h:inputText value="#{ajaxBean.name}">
<f:ajax render="otherbox" execute="#this" event="keyup"></f:ajax>
</h:inputText>
<h:inputText id="otherbox" value="#{ajaxBean.name}"></h:inputText>
</h:form>
And the bean
#Named(value = "ajaxBean")
#Dependent
public class AjaxBean {
public AjaxBean() {
}
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
That code does not work. Can anyone help me?
Thanks
Your question is not about Ajax or JSF. It is a JavaScript question.
You can access and modify items with JavaScript.
Add this JavaScript codes between <h:head></h:head>
<script>
function copyField()
{
document.getElementById("field2").value = document.getElementById("field1").value;
}
</script>
And your page:
<h:form id="myform" prependId="false">
<h:inputText id="field1" value="#{myBean.name}" onkeyup="copyField();" />
<h:inputText id="field2" value="#{myBean.name}"></h:inputText>
</h:form>
Take attention to prependId="false" to avoid mixing ids.
See also:
JSF: Why prependId = false in a form?
I think you are mixing up JSF and CDI. #Dependent says that the bean is in the dependent pseudo-scope (which is anyways the default-scope for CDI-beans), so every time you make a request the bean will be reinstanciated and the bean can not hold any state. Look here for an explanation of the scopes and especially for what the dependent scope is used for.
So first of all you have to use some different scope, #RequestScoped should be enough for your task. And as I do not see any use of CDI here, use #ManagedBean instead of #Named - so the default scope for the bean will be the request scope.
Try this:
#ManagedBean
public class AjaxBean {
...
}
I have a RequestController(#ManagedBean and #ViewScoped) it is view scoped because we are using some ajax calls.
I have a dataTable with result and each result with a button
<p:commandButton action="#{requestController.requestDetail()}" icon="ui-icon-search" title="Detalhes">
<f:setPropertyActionListener target="#{requestController.backing.selectedRequestVO}" value="#{order}" />
</p:commandButton>
This method is receiving the selected object of my dataTable and is set on the session, it is working, the problem is that I don't know how to get this session object from my view.
public void requestDetail() throws IOException {
FacesContext context = FacesContext.getCurrentInstance();
context.getExternalContext().getSessionMap().put("requestDetail",backing.selectedRequestVO);context.getExternalContext().redirect(context.getExternalContext().getRequestContextPath() + "/views/request/detail.html");
}
I need to access it from my view because this object has the request details.
It's just available by the attribute name which you specified yourself.
#{requestDetail}
Note that this is not the correct approach. You should have another session scoped managed bean which you inject as #ManagedProperty in the view scoped managed bean and then set the request detail as its property.
#ManagedBean
#ViewScoped
public class RequestController {
#ManagedProperty("#{requestDetail}")
private RequestDetail requestDetail;
public String requestDetail() {
requestDetail.setSelectedRequestVO(backing.getSelectedRequestVO());
return "/views/request/detail.html?faces-redirect=true";
}
// ...
}
with
#ManagedBean
#SessionScoped
public class RequestDetail {
private RequestVO selectedRequestVO;
// ...
}
which you then access as follows
#{requestDetail.selectedRequestVO}
<h:form>
<h:commandButton value="Buy" styleClass="button-buy" actionListener="#{basketCount.incrementBasketCount}" immediate="true">
</h:commandButton>
</h:form>
jsf2 part:
<li class="basket">
#{basketCount.basketCount}
</li>
faces-config:
<managed-bean>
<managed-bean-name>basketCount</managed-bean-name>
<managed-bean-class>main.BasketCount</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
</managed-bean>
simple bean for action listening:
package main;
import java.io.Serializable;
public class BasketCount implements Serializable {
private static final long serialVersionUID = -4576074045587545642L;
int inBasketCount = 0;
public void incrementBasketCount(javax.faces.event.ActionEvent event) {
inBasketCount++;
}
public int getBasketCount() {
return inBasketCount;
}
}
use case:
1. click on "Buy" button
2. content of basket is incremented
3. click Shift-Ctrl-Del (clean cookie and cache) in FF and Refresh
4. counter of basket remained same
As I understand, session scope specifies,that this counter (step 2) will be incremented in session scope only, and after cookies,cache clean up should be resetted?
The problem,that it does not.
Resolved by providing persistent cookies