<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
Related
I have a simple webapp which allows the user to create transactions, and on another page the user can see all past transactions. I would like:
To have the dataTable be up-to-date when I open the past transaction page
To update the dataTable when I create a transaction on the creation page
I am not sure if this can be covered by one or two functionalities. Also, I am not sure how to decouple the functionalities. Should the creation of a transaction trigger the refresh of the dataTable, or should the dataTable itself find new entries in the DB ?
The past transactions page:
My TransactionListModel
package model;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.enterprise.context.SessionScoped;
import javax.inject.Named;
import entity.Transaction;
#Named
#SessionScoped
public class TransactionListModel implements Serializable {
private static final long serialVersionUID = 1L;
private List<Transaction> txList;
#PostConstruct
public void init() {
txList = new ArrayList<Transaction>();
}
public List<Transaction> getTxList() {
return txList;
}
public void clearList(){
txList = new ArrayList<Transaction>();
}
}
My Transaction view
<!-- Fill the table before rendering -->
<f:event type="preRenderView" listener="# {transactionListController.findAllTx()}" />
<h:form id="alltxform">
<p:dataTable id="tableAllTransactions" var="transaction"
value="#{transactionListModel.txList}">
<f:facet name="header">Transactions</f:facet>
<p:column headerText="Id">
<h:outputText value="#{transaction.id}" />
</p:column>
</p:dataTable>
</h:form>
My TransactionList Controller
#Named
#RequestScoped
public class TransactionListController implements Serializable {
private static final long serialVersionUID = 1L;
#Inject
private Logger log;
#Inject
private TransactionService txService;
#Inject
private TransactionListModel txListModel;
public void findAllTx() {
txListModel.clearList();
txListModel.getTxList().addAll(txService.findAllTx());
}
public void reset() {
if (txListModel.getTxList() != null) {
txListModel.clearList();
}
}
}
The creation page
There is a simple textInputField (bound to a model) with a button:
<h:commandButton id="sendtx" value="Send" styleClass="ui-priority-primary">
<f:actionListener binding="#{transactionXmlController.sendTx()}" />
</h:commandButton>
The called method:
public void sendTx() {
FacesMessage message;
if (!transactionService.sendTx(transactionXmlEditableModel.getXml()).equals("OK"))
message = new FacesMessage(FacesMessage.SEVERITY_ERROR, "Error", "KO");
else {
message = new FacesMessage(FacesMessage.SEVERITY_INFO, "Success", "OK");
}
fc.addMessage(null, message);
}
So far, this works.
My Questions
How do I reload the dataTable with AJAX ?
I would like the dataTable to update even if it has been opened in another tab before the creation of a new transaction. How to do this ?
How to replace my "f:event type="preRenderView" with a viewAction in order to fill the dataTable before rendering the page ?
I'm not sure how you would update the table in another tab, without something like <p:poll> but to update your table with Ajax you can do something like:
<h:commandButton id="sendtx" value="Send" styleClass="ui-priority-primary">
<f:ajax listener = '#{transactionXmlController.sendTx()}' render="alltxform:tableAllTransactions" />
</h:commandButton>
My actual scenario is a simple JSF project that uses Mojarra 2.2.5.
I'm trying to get programmatically a component instance (via "findComponent" method or binding ...) and set some attributes (click on "ChangeColor" button).
After that, using any other action (for example clicking on "Send" button), the previous changes are ignored !!
It seems that changeColor method don't update the ViewState !
The sample code is the following:
<h:form id="form">
<h:panelGrid columns="1">
<h:inputText id="input" binding="#{page9.input}"/>
<h:commandButton value="Change BackColor" action="#{page9.changeColor}"/>
<h:commandButton value="Send" action="#{page9.dummy}" />
</h:panelGrid>
</h:form>
And the relative RequestScope bean
#ManagedBean(name="page9")
#RequestScoped
public class Page9 implements Serializable {
private static final long serialVersionUID = 1L;
private HtmlInputText input;
public HtmlInputText getInput() {
return input;
}
public void setInput(HtmlInputText input) {
this.input = input;
}
public void changeColor(){
FacesContext fc = FacesContext.getCurrentInstance();
HtmlInputText hit = (HtmlInputText) fc.getViewRoot().findComponent(":form:input");
hit.setStyle("background-color:blue");
}
public void dummy(){
}
}
Some important considerations:
1) I must use RequestScope for compatibility reasons.
2) Setting javax.faces.PARTIAL_STATE_SAVING to "false" all works fine (!).
3) Trying to use MyFaces 2.2.3 libraries all works fine (!).
What do you think about ?
Thanks.
Hi there i currently have a web page that uses ajax on submit to display the message the user entered on the same page below the input box, what i am wondering, if it is possible to keep a record of all messages inputted such as message 1, message 2 etc all displayed under them?
what is the best method for this ? also is there a way to do this with out the user having to press the submit button each time ?
this is my code so far :
<h:body>
<h3>JSF 2.0 + Ajax Hello World Example</h3>
<h:form>
<h:inputText id="name" value="#{helloBean.name}"></h:inputText>
<h:commandButton value="Welcome Me">
<f:ajax execute="name" render="output" />
</h:commandButton>
<h2><h:outputText id="output" value="#{helloBean.sayWelcome}" /></h2>
</h:form>
</h:body>
my bean
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import java.io.Serializable;
#ManagedBean
#SessionScoped
public class HelloBean implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSayWelcome(){
//check if null?
if("".equals(name) || name ==null){
return "";
}else{
return "Ajax message : Welcome " + name;
}
}
}
First you will need to change your bean. Make the attribute a List<String> to store all of the messages.
After that, to show the list you need to change output to a component that allows for showing all elements of the List; v.g. dataTable.
Also, you will need to invoke an action method in you ajax request, because your application will need to execute some logic (add name to the list).
Completely edited:
Maybe I was mixing problems and misinterpreted. After simplifying my code the question simplifies to: How can I prevent the <p:commandButton> from executing it's action method on page refresh (like when you hit F5 inside browser window)?
JSF Code:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui">
<h:body>
<h:form>
<h:outputText value="#{bugBean.number}" />
<h:outputText value="#{bugBean.isComplete()}" />
<p:commandButton id="entryCommand" value="add"
action="#{bugBean.increase()}" update="#form" oncomplete="#{bugBean.complete()}"/>
</h:form>
</h:body>
</html>
backing bean code:
package huhu.main.managebean;
import java.io.Serializable;
import javax.enterprise.context.SessionScoped;
import javax.inject.Named;
#Named
#SessionScoped
public class BugBean implements Serializable {
private static final long serialVersionUID = 1L;
private int number;
private boolean isComplete = false;
public void increase(){
number++;
}
public void complete(){
isComplete = true;
}
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
public boolean isComplete() {
return isComplete;
}
public void setComplete(boolean isComplete) {
this.isComplete = isComplete;
}
}
Update:
Even if I remove the oncomplete stuff like this an click the <p:commandButton> just once, the counter goes up on every page refresh.
<h:form>
<h:outputText value="#{bugBean.number}" />
<p:commandButton id="entryCommand" value="add"
action="#{bugBean.increase()}" update="#form"/>
</h:form>
The construct was lacking Ajax-support due to a missing head definition as it seems. In this case I just added <h:head/> right above the <h:body>-tag and everything worked fine.
Thanks to all contributors!
I think that the action method increase() is not called on each page refresh, but it's called the complete() method instead, and this is probably making you think that the action method has been called.
The oncomplete attribute inside the p:commandButton indicates a client side action, and so a JS method, and not a server action: the EL executes #{bugBean.complete()} when parses it on each page refresh.
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}" />