On page I have checkbox which enables/disables h:inputText and h:selectOneMenu. That works fine until I refresh the page. Value of checkbox is probably cached by browser.
So, when the checkbox was set on "true" after refresh both controls are enabled. selectOneMenu is rendered corresponding to value set in init() method, but selectBooleanCheckbox and inputText isn't. How can I fix that? I use Firefox browser.
Backing bean is simple, one property and one method - init in which value is set to false.
#ManagedBean(name="newBean")
#ViewScoped
public class NewBean implements Serializable {
private boolean booleanValue;
public NewBean() {
}
public void init()
{
booleanValue = true;
}
public boolean isBooleanValue() {
return booleanValue;
}
public void setBooleanValue(boolean booleanValue) {
this.booleanValue = booleanValue;
}
}
Page source:
<h:body>
<f:metadata>
<f:viewAction action="#{newBean.init()}"></f:viewAction>
</f:metadata>
<h:form>
<h:outputText value="#{newBean.booleanValue}"></h:outputText>
<br/>
<h:selectBooleanCheckbox value="#{newBean.booleanValue}" id="selected">
<f:ajax event="change"
render="enabledInput disabledInput enabledMenu"></f:ajax>
</h:selectBooleanCheckbox>
<br/>
<h:inputText disabled="#{newBean.booleanValue}" id="enabledInput"></h:inputText><br/>
<h:selectOneMenu disabled="#{!newBean.booleanValue}" id="enabledMenu">
<f:ajax></f:ajax>
</h:selectOneMenu>
</h:form>
</h:body>
EDIT: Added some screenshots so it will be easier to understand the problem.
Correct: Page opened by user (checkbox is checked, and it corresponds to bean value, textbox is disabled, menu is enabled):
Correct: User unchecked checkbox (checkbox is unchecked, value on bean is false too, textbox is enabled, menu is disabled):
ISSUE: after unchecking user refreshed page. Value on bean is true, but checkbox is still unchecked. Also, textbox and menu are BOTH enabled.
Hey there I didn't quite understand your problem but I'd like to point two things.
<f:metadata>
<f:viewAction action="#{newBean.init()}"></f:viewAction>
</f:metadata>
Must be in the < h:form /> for the action to take effect.
And also if you want the method init to take effect before you create the new instance of the view add the annotation #PostConstruct or simply put the code
" booleanValue = true; " inside the constructor of the view.
Hopefully I may be of help.
Related
My screen looks like this
The problem is that, when I press the Reset Button, the Code input field does not clear, as it was supposed to.
The jsf is the following:
<h:form id="form1">
<h:inputText id="code" value="#{MyBean.data.code}" />
<a4j:commandButton immediate="true"
action="#{MyBean.clear}" render="form1" update="#form">
</a4j:commandButton>
<h:outputText value="#{session.lastAccessedTime}">
<f:convertDateTime pattern="HH:mm:ss.SSS" type="date" />
</h:outputText>
</h:form>
The bean code is the following:
public class MyBean {
DataInnerClass data = new DataInnerClass();
//getter and setter for data
public class DataInnerClass {
private String code;
//getter and setter for code
public DataInnerClass() {
super();
}
}
public void clear() {
data = new DataInnerClass();
Logger.getLogger( MyBean.class.getName() ).log(Level.SEVERE, "data.code="+data.code);
//logs data.code=null
}
}
When I press the Reset button, the log shows that the value of the field code has become null (its no longer 'ZZ'); i also know that the screen refreshes successfully, because i have displayed the current time, which updates after every click. So the backing bean property changes, the screen refreshes, and still the input field keeps the same value. Do you have any idea why this is happening?
I found useful BalusC's answer on: How can I populate a text field using PrimeFaces AJAX after validation errors occur?
I understand from there that, in the case of some validation error, the input field will keep the value entered by the user, and will be out of sync with the backing bean. I must emphasize that in my case, there were no validation errors, but still, adding an <f:ajax resetValues> to the commandButton worked for me.
A concrete example of the resetValues attribute is on https://jsflive.wordpress.com/2013/06/20/jsf-22-reset-values/
Finally, my button tag looks like this:
<a4j:commandButton immediate="true"
action="#{MyBean.clear}" render="form1" update="#form">
<f:ajax render="code" resetValues="true" />
</a4j:commandButton>
I have a JSF application in wich i'm using ui:composition/ui:include to display some elements inside a page like in the following code
template.xhtml
...
<h:body>
...
<h:panelGroup id="mainPanel">
<ui:include src="#{myBean.page}"/>
</h:panelGroup>
...
</h:body>
items-list.xhtml
<ui:composition>
...
<h:form>
<p:dataTable var="item" value="#{myBean.items}">
<p:column>
<h:commandLink action="#{myBean.loadItemDetail(item)}"
process="#this"
update="mainPanel">
<h:outputText value="#{item.name}"/>
</h:commandLink>
</p:column>
</p:dataTable>
</h:form>
...
</ui:composition>
items-detail.xhtml
<ui:composition>
<h:form>
<!-- Some code to display and modify the item details-->
</h:form>
<ui:composition>
MyBean.java
#ManagedBean
#ViewScoped
public class MyBean {
private String page;
private List<Item> items;
private ItemDetail itmDetail;
#PostConstruct
private void init() {
page = "items-list.xhtml"
items = ... //some logic to populate the items list
}
public void loadItemDetail(Item item){
itmDetail = ... //some logic to get the item's detail
page = "item-detail.xhtml"
}
}
The first time I click on an item to see the details it works fine but after that, if I click on the browser's back button and try to load a different item details it keeps showing me the details of the first item.
I check the JSF lifeCycle for each call and although in every call the application goes through all the satages, only the first one calls the bean method locadItemDetail. is there a reason why my method is being ignored after the first success call? is there some kind of cache on JSF where my data is bean taken from instead of my Bean?
Also i tried to avoid this behavior implementing a filter as is suggest in this post and it kind of works but now when I click browser's back button it show me an annoying page preventing me from resend the form; is there a way to prevent that?
Note:
I know that i could change the app to use GET method instead of POST to avoid this cache problem but it will required some serious changes over the app so that's not an option.
Any help or guidance about why could this be happening will be appreciated.
Assume we have a form. One p:inputText visible but user can add many more using p:commandButton. All this values have to be provided when submitting with another p:commandButton. Issue arises when user tries to add more than one empty input fields. All of them are marked required="true" so validation error appears when one field is empty and user try to add another.
The best would be to allow to add as many fields as user needs, then fill them in and submit.
JSF:
<h:form id="myForm">
<p:commandButton value="add" actionListener="#{testBean.addNewItem()}" update="#form"/>
<p:commandButton value="done" update="#form,:p"/>
<br/>
<ui:repeat value="#{testBean.list}" var="l">
<p:inputText value="#{l.name}" required="true"/>
<br/>
</ui:repeat>
</h:form>
<p:messages autoUpdate="true"/>
<p:panel id="p">
#{testBean.list}
</p:panel>
Backing bean does nothing fancy. Only provides getter and setter for list. It also adds empty string to the list.
#ManagedBean
#ViewScoped
public class TestBean implements Serializable {
private List<Item> list = new ArrayList<Item>();
public List<Item> getList() { return list; }
public void setList(List<Item> list) { this.list = list; }
public void addNewItem() { list.add(new Item()); }
}
I could:
Remove requirement for field - not an option.
Add immediate="true" for adding button. Validation is not a problem now but it causes all values that was filled in but not submitted to disappear. And I need to update #form because only then newly added fields will be rendered by ui:repeat.
I tried to add process="#this" for adding button. Unfortunately that didn't change a thing. Input field values are not processed, but form needs to be updated. I am loosing not submitted values as above.
What am I missing? Is there any workaround?
Just let the required attribute check if the "done" button is pressed. The button's own client ID is present as a request parameter if that's the case. Request parameters are available by #{param} mapping. You can use button's binding attribute to bind the physical component to the view so that you can grab its UIComponent#getClientId() elsewhere. Finally just do the boolean logic.
E.g.
<p:commandButton binding="#{done}" ... />
...
<p:inputText ... required="#{not empty param[done.clientId]}" />
Will something like this work?
<p:inputText value="#{l.name}" required="#{l.name != null ? true : false}"/>
This will enable the newly added inputText components to not be required but enforce the items already in the list to be required.
I have a dataTable. The data of the dataTable is filled via ajax. A row of the table contains among other things form elements like a button. The button in the datatTable should refer to another page but if I click on them the current page is reloaded.
Here some code:
the backing bean:
#ManagedBean(name="bean")
#SessionScoped
public class Bean {
private List<String> data;
#PostConstruct
public void postConstruct() {
data = new ArrayList<String>();
}
public void fillTable() {
data.add("E1");
data.add("E2");
data.add("E3");
}
public String outcome(){
return "/faces/test/edit.jsf";
}
public List<String> getData() {
return data;
}
public void setData(List<String> data) {
this.data = data;
}
}
the page:
<!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:h="http://java.sun.com/jsf/html" >
<h:body>
<h:form id="form">
<h:commandButton value="fillTable">
<f:ajax listener="#{bean.fillTable()}" render="#form"/>
</h:commandButton>
<h:dataTable id="table" var="data" value="#{bean.data}">
<h:column>
<h:outputText value="#{data}" />
</h:column>
<h:column>
<h:commandButton value="edit" action="#{bean.outcome}" />
</h:column>
</h:dataTable>
</h:form>
</h:body>
</html>
I know that this has something to do that the form is already in the dom and the button are lazy loaded into the page (if someone could be more specific I would be very pleased).
Although if I change the Scope of the backing bean to SessionScope it works. The button redirect to the right page. Why?
Although if I change the Scope of the backing bean to SessionScope it works. The button redirect to the right page
The bean should have been placed in the view scope. The session scope is too broad and would only risk unintuitive behaviour when the same view is been opened in multiple browser windows/tabs in the same session.
The explanation is as follows: when a form is submitted, JSF needs to identify the command button pressed in order to invoke the associated action method. As the command button is been placed in side a datatable, JSF needs to iterate over its datamodel first. But if the datamodel has been changed, or is empty, then JSF won't be able to identify the command button. Hence the action won't be invoked.
When the bean is in the request scope, then it will be trashed by end of response and recreated during every new request, including ajax requests. All of the bean's properties will obviously get the default values again, so also the data property in your case.
See also:
commandButton/commandLink/ajax action/listener method not invoked or input value not updated - particularly point #4.
How to choose the right bean scope?
This odd behavior only happen in Firefox (specifically Firefox 8). So I have a dataTable that I can do multiple selection. A submit button, that will display a list of selected items to a dataList and to a dialog. If the user did not select anything, then a error msg come up asking the user to select something. The dialog will not appear if the user select nothing. The below code does all that. However FireFox behaves oddly if you do these follow:
Click to select an item on the dataTable
Then refresh (F5 or Ctl + R) the page (you can see the selection got clear off)
Then click submit, it show whatever I just selected.
This is unexpecting, since the refresh should clear out whatever you just select due to nature of #ViewScoped bean. This behavior only happen in Firefox. IE 8 behave correctly for me. Is this a bug, or am I doing something wrong here?
Mojarra 2.1 + PrimeFaces3.0 Final + Tomcat 7
UPDATE: I did some debugging, when I refresh page, the value of the array selectedFoods become null, but for some odd reason, when it get to public void checkSelection(), it hold the value of the previous selection. So odd.
Here is my code.
<p:growl id="messages" showDetail="true" />
<p:messages id="msgs"/>
<h:form id="form">
<p:dataTable value="#{viewBean.foodList}" var="item"
selection="#{viewBean.selectedFoods}"
selectionMode="multiple"
rowKey="#{item}">
<p:column>
#{item}
</p:column>
<f:facet name="footer">
<p:commandButton value="Submit" update=":form:display :dataList"
action="#{viewBean.checkSelection}"/>
</f:facet>
</p:dataTable>
<p:dataList id="display" value="#{viewBean.selectedFoods}" var="item"
itemType="disc">
#{item}
</p:dataList>
</h:form>
<p:dialog id="dialog1" widgetVar="dialog1" dynamic="true" width="200">
<p:dataList id="dataList" value="#{viewBean.selectedFoods}" var="item"
itemType="disc">
#{item}
</p:dataList>
</p:dialog>
Here is my managed bean
#ManagedBean
#ViewScoped
public class ViewBean implements Serializable {
private List<String> foodList;
private String[] selectedFoods;
#PostConstruct
public void init() {
foodList = new ArrayList<String>();
foodList.add("Pizza");
foodList.add("Pasta");
foodList.add("Hamburger");
}
public void checkSelection(){
RequestContext requestContext = RequestContext.getCurrentInstance();
if(selectedFoods.length > 0){
requestContext.execute("dialog1.show()");
}else{
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("Error", "Please select"));
requestContext.addPartialUpdateTarget("messages");
}
}
//setter, getter
}
Your code is fine. What you're seeing is because of something that is supposed to be a feature of Firefox (I was able to reproduce this on FF4). The selection model for p:dataTable is implemented with a hidden form field. When reloading a page, Firefox tries to save and restore form field values that have changed so that you don't lose what you entered. You can observe this by adding a <h:inputText/> to your view, typing something in the input, and reloading.
I'm not sure that the Firefox team meant for this to apply to hidden form fields, but I figure there's a decent chance that they did. I plan to file a bug report with Primefaces to either initialize the hidden input or to read the input on load to make the p:dataTable selection match. Either solution should result in the rendered selection and the hidden selection model to be in sync.