a4j:support in a reRender is not working - jsf

I have a button. If this is pressed, a checkbox should be rendered.
This of course works pretty well. The checkbox should, when changed call a function, which should just System.out.println() something so I see it's called.
The problem is: just the simple checkbox function, without the rerendering works pretty well. But as soon as the a4j:support is rerendered, it's not working, the System.out.println() is never called
This looks so easy, but I don't know why it's not working at all!
Any hint/trick?
This is old environment, so JSF 1.2 only.
My xhtml
<s:div id="sdBoolCheckboxtest">
#{testController.testRerenderBool}
<s:div id="sdRerender" rendered="#{testController.testRerenderBool}">
<h:selectBooleanCheckbox id="myscheckbox" value="#{testController.testBool}">
<a4j:support ajaxSingle="true" event="onclick" immediate="true"
status="globalStatus" action="#{testController.testCheckbox()}" />
</h:selectBooleanCheckbox>
</s:div>
</s:div>
</h:form>
My Java class:
#Name("testController")
#AutoCreate
public class TestController {
private boolean testBool = false;
public boolean isTestRerenderBool() {
return testRerenderBool;
}
public void setTestRerenderBool(boolean testRerenderBool) {
this.testRerenderBool = testRerenderBool;
}
private boolean testRerenderBool;
public void switchtestRerenderBool(){
System.out.println("switch");
testRerenderBool = !testRerenderBool;
}
public void testCheckbox(){
System.out.println("drin");
}
public boolean isTestBool() {
return testBool;
}
public void setTestBool(boolean testBool) {
this.testBool = testBool;
}
}

Okay, i got it working, with these changes:
First i added #Scope(ScopeType.CONVERSATION) to the TestController
#Name("testController")
#AutoCreate
#Scope(ScopeType.CONVERSATION)
public class TestController {
...
}
And as a second change, I changed the <s:div to an <a4j:outputPanel
<a4j:outputPanel id="sdBoolCheckboxtest">
This solved my problem, but I'm still wondering why I need the #Scope(ScopeType.CONVERSATION) (I found the hint with the a4j:outputPanel here)
Any explanation would be helpful, thanks!

Related

Trigger listener clicking on ace:textEntry

I'm using JSF 2.0 and I want to invoke a function defined in a Java controller when I click on an ace:textEntry.
I tried in this way:
<ace:textEntry readonly="true" value="#{myController.getValue()}"
onclick="#{myController.myFunc()}"/>
but when my page is open, the click event is called instantly.
So, I tried with:
<ace:textEntry readonly="true" value="#{myController.getValue()}">
<ace:ajax event="click" listener="#{myController.myFunc()}"/>
</ace:textEntry>
but my page is not rendered.
Is there another way to implement this behaviour ?
PS: I can use similar JSF components instead of ace:textEntry too.
First, you do not access getters directly in JSF for value backing - you access the property. Secondly, you should call the listener with the correct signature. To correct your example I would first rewrite the call like this,
<ace:textEntry readonly="true" value="#{myController.value}">
<ace:ajax event="click" listener="#{myController.myFunc}"/>
</ace:textEntry>
Then define MyController, like this;
#Named
#ViewScoped
public class MyController {
private value;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public void myFunc(javax.faces.event.AjaxBehaviorEvent event) {
/* Do somethinig here... */
}
}

poll doesn't work with setted var

I want to use one html page with two ManagedBeans. Depending on the parameter in the URL, I want to set the bean name through JSTL variable. For example:
<c:set var="bean" value="#{webModule1}" scope="request" />
or
<c:set var="bean" value="#{webModule2}" scope="request" />
I have class which was use all this time, so for sure this works:
#ManagedBean(name = "webModule1")
#ViewScoped
public class WebModule1 implements Serializable {
protected WebModulesFormBean form;
#PostConstruct
public void init() {
if (!firstInit()){
this.form= new WebModulesFormBean();
}
//some code
}
public void process() {
if(this.form.isActive()){
//some code
}
}
}
And new one:
#ManagedBean(name = "webModule2")
#ViewScoped
public class WebModule2 extends WebModule1 {
public void process() {
if(this.form.isActive()){
//code with some changes
}
}
}
This solutions works with value attribute and form in not null, for example:
<p:treeTable value="#{bean.form.root}" var="node" id="modulesTree">
But I have problem with this piece of code:
<p:poll listener="#{bean.process()}" widgetVar="documentOutcome" autoStart="#{bean.form.start}" update="modulesTree" async="false"
interval="1" id="myPoll2" />
When listener is called, NullPointerException appears.
And this problem is with all p:polls (I have a few), so this is not a problem with method code.
Problem is that 'form' is null, although at the beginning variable 'form' is initialized and treeTable is shown at the page. So 'form' starts to be null when the listener is called.
Thanks!
I have a solution!
The problem was with:
<c:set var="bean" value="#{webModule1}" scope="request" />
scope="request" was not enough and in my understanding this scope meant that when poll was called, a new bean reference was created and form variable was null because it was not a firstInit().
scope="view" is the solution.
Thank you for comments!

#ConversationScoped bean reconstructed during page-to-page navigation

I just found a strange behavior when I change from one page to another.
I'm using CDI, Jsf 2.2 API 2.2.8, Omnifaces 2.2, Primefaces 5.2, wildfly 8.2.
Most of the controllers and pages work as expected, but some of them, when I access the page, call the method #PostConstruct, which starts the conversation, then, when I leave the page, the #PostConstruct is called again. I realized that something in page.xhtml is the cause, so I started to look for it. But is a strange behaviour anyway.
Following my code and some examples:
Controller which uses abstract class methos like beginconversation() and list()
import javax.inject.Named;
import javax.enterprise.context.ConversationScoped;
#Named
#ConversationScoped
public class PromptConfigurationController extends BaseController<PromptConfiguration> implements Serializable {
public PromptConfigurationController() {
super(PromptConfiguration.class);
}
#PostConstruct
public void init() {
list();
loadFilters();
}
}
Abstract class
public abstract class BaseController<T extends BaseEntity> {
public void list() {
logger.info("list()");
items = getService().findAll(entityClass);
item = null;
beginConversation();
}
protected void beginConversation() {
logger.info("beginConversation()");
if (conversation != null && conversation.isTransient()) {
conversation.begin();
conversation.setTimeout(CONVERSATION_TIMEOUT);
logger.info("Conversation iniciada: " + conversation.getId());
}
}
}
some xhtml pages which I found problem and the solution (when I found) was:
Error:
<f:convertDateTime pattern="#{webChatSearchController.dateHelper.getLocalizedDatePattern()}" />
The method above just return a pattern.
Working
<f:convertDateTime dateStyle="dd/MM/yyyy" pattern="dd/MM/yyyy" />
Error:
<p:commandButton id="commandButton-active" action="#{satisfactionSurveyController.changeQuestionStatus(true)}" update="form-content" binding="#{satisfactionSurveyController.activeButton}" value="#{bundle['common.active.3.message']}">
Working:
<p:commandButton id="commandButton-active" action="#{satisfactionSurveyController.changeQuestionStatus(true)}" update="form-content" value="#{bundle['common.active.3.message']}" disabled="#{satisfactionSurveyController.disableActiveButton}">
The problem was just the "binding".
Error:
<p:dataTable id="dataTable-group-email" var="emailMonitor" value="#{emailMonitorController.listEmailGroup}" selectionMode="single" rowKey="#{emailMonitor}" filteredValue="#{emailMonitorController.listEmailGroupFiltered}">
Working:
<p:dataTable id="dataTable-group-email" var="emailMonitor" value="#{emailMonitorController.listEmailGroup}" selectionMode="single" rowKey="#{emailMonitor}" >
Just removing 'filteredValue' started working. But without it, I can't use the filter properties.
The navigation is made by a menu of primefaces, all the pages are the same logic:
<p:menuitem id="satisfactionSurvey" action="#{satisfactionSurveyController.listPage}" value="#{bundle[satisfactionSurvey.message']}" ajax="false" immediate="true">
<f:param name="nocid" value="true" />
</p:menuitem>
and the Method:
public String listPage() {
return baseViewPath + "/list.xhtml?faces-redirect=true";
}

Input fields hold previous values only if validation failed

I came up with a strange problem. I tried to isolate the problem so following is my simplified code.
public class MyBean {
private List<Data> dataList;
Data selectedData;
public MyBean() {
dataList = new ArrayList<Data>();
dataList.add(new Data("John", 16));
dataList.add(new Data("William", 25));
}
public List<Data> getDataList() {
return dataList;
}
public void edit(Data data) {
selectedData = data;
}
public void newData() {
selectedData = new Data(null, null);
}
public Data getSelectedData() {
return selectedData;
}
public class Data {
String name;
Integer age;
Data(String name, Integer age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
}
xhtml:
<rich:modalPanel id="pop">
<h:form>
Name: <h:inputText value="#{myBean.selectedData.name}" required="true" id="txtName"/><br/>
Age : <h:inputText value="#{myBean.selectedData.age}" required="true" id="txtAge"/>
<a4j:commandButton value="Save"/>
<a4j:commandButton value="Close" onclick="Richfaces.hideModalPanel('pop');return false;"/>
<br/>
<rich:message for="txtName"/><br/>
<rich:message for="txtAge"/>
</h:form>
</rich:modalPanel>
<h:form>
<rich:dataTable value="#{myBean.dataList}" var="data">
<rich:column>#{data.name}</rich:column>
<rich:column>
<a4j:commandLink value="Edit" action="#{myBean.edit(data)}" reRender="pop" oncomplete="Richfaces.showModalPanel('pop')"/>
</rich:column>
</rich:dataTable>
<a4j:commandButton value="New" action="#{myBean.newData()}" reRender="pop" oncomplete="Richfaces.showModalPanel('pop')"/>
</h:form>
This is the path to error:
Load the page
Click the "Edit" link in first row(popup displays)
In popup, clear the "Age" field and click "Save".(Required message shown)
Click cancel(without filling "Age" field)
Click second link.
Now it shows irrelevant data(previous data). - This is the problem
Even when I click "New" button it shows incorrect data.
This happens only if a validation is failed in the popup.
Is there a solution for this?
This problem is in JSF 2 also recognized and explained in detail in the following answer: How can I populate a text field using PrimeFaces AJAX after validation errors occur? If you were using JSF 2, you could have used OmniFaces' ResetInputAjaxActionListener or PrimeFaces' <p:resetInput> or resetValues="true" for this.
To the point, you need to clear the state of the EditableValueHolder component when it's about to be ajax-rendered, but which isn't included in the ajax-execute. To clear the state, in JSF 2 you would have used the convenience method resetValue() for this, but this isn't available in JSF 1.2 and you need to invoke the 4 individual methods setValue(null), setSubmittedValue(null), setLocalValueSet(false), setValid(true) to clear the state.
To figure out which components are to be ajax-rendered, but aren't been ajax-executed, in JSF 2 you would have used PartialViewContext methods for this, but this is not available in JSF 1.2 which hasn't standardized ajax yet. You'd need to fiddle with RichFaces specific ajax API in order to figure that. I can't tell that from top of head, so here's a kickoff example assuming that you already know the components which needs to be cleared. Imagine that the form in your popup has id="popForm" and the name input field has id="nameInput", here's how you could clear it inside the newData() method:
UIInput nameInput = (UIInput) context.getViewRoot().findComponent("popForm:nameInput");
nameInput.setValue(null);
nameInput.setSubmittedValue(null);
nameInput.setLocalValueSet(false);
nameInput.setValid(true);
do one thing on cancel action set all popup values null. now in your next click all values set to be default.
or on click set all previous values null. and set all respective values after that.
I had the same problem. if you are using Primefaces, the solution is as simple as putting resetValues="true" on your p:commandLink or p:commandButton that loads the selected item.
After validation failed if you want to remain same as input data which you have pass as submission parameter, then set value attribute as your form bean name as mention below i.e.
<input type="text" id="fname" path="fname" value="${myFormBean.fname}"/>

Netbeans tells "Unknown property" on <p:poll listener>

I havent worked out how to call/invoke a method dynamically without using the #PostContruct method and initialising # the page creation.
At the moment I am simply trying to get the primeface p:poll example working. I have placed the method in its own class for now to keep it clean and simple & looks like so:
#ManagedBean(name="counterBean")
#SessionScoped
public class CounterBean implements Serializable {
private int count;
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
public void increment(ActionEvent actionEvent) {
setCount(getCount() + 1);
}
}
And then the xhtml code:
<h:form>
<h:outputText id="txt_count" value="#{counterBean.count} " />
<p:poll interval="3" listener="#{counterBean.increment}" update="txt_count"/>
</h:form>
Intellisense within netbeans tells me that the "increment" part of #{counterBean.increment} is an "Unknown Property" i.e. it cant find the method. So how can I get JSF to recognise and invoke this method from the xhtml?
Well after a some head scratching the p:poll component started working after a slight adaptation from the primefaces demo & manual. Change the p:poll listener to actionListener:
<h:form>
<h:outputText id="txt_count" value="#{counterBean.count} " />
<p:poll interval="3" actionListener="#{counterBean.increment}" update="txt_count"/>
</h:form>
Also ensure that your html page/template is surrounded by the <f:view contentType="text/html"> tag
Hope this helps someone & thanks to BalusC for his help in debugging this.

Resources