selectOneMenu sets field to null after being changed - jsf

I try to do something that is very similar to this richfaces example. I have a form that describes custom ID validation in case that you have not selected one of the predefined ones, else the form will be disabled. So disabled expression for the form members would go to the next method:
public boolean isPredefinedValidator() {
return !currentProjectRegField.getIdValidation().getIdType().equals(IdValidatorType.NONE);
}
that is invoked like this:
disabled="#{accountHome.isPredefinedValidator()}"
and here is the selector for the predefined validator:
<h:selectOneMenu value="#{accountHome.currentProjectRegField.idValidation.idType}"
rendered="#{!(empty accountHome.currentProjectRegField or empty accountHome.currentProjectRegField.idValidation)}">
<a4j:support event="onchange" reRender="customIdValidator"/>
<s:convertEnum />
<s:enumItem enumValue="NONE" label="#{messages['IdValidatorType_enum.NONE']}"/>
<s:enumItem enumValue="USA_ID" label="#{messages['IdValidatorType_enum.USA_ID']}"/>
<s:enumItem enumValue="MEXICO_ID" label="#{messages['IdValidatorType_enum.MEXICO_ID']}"/>
</h:selectOneMenu>
The issue is, when the method isPredefinedValidator() is invoked on a4j rerender (on disabled EL), I receive NPE.
Caused by: java.lang.NullPointerException
at com.whatever.something.action.AccountHome.isPredefinedValidator(AccountHome.java)
And when I try to debug - turns out that the value that has been set from the selectOneMenu is null.
Does it mean that reRender and setting value to the variable happens async, and there is a race condition? And what is the correct solution for this case?

Some black-magic configuration in the rich:modalPanel that contains the h:selectOneMenu resolved this issue. It goes like this <rich:modalPanel ... domElementAttachment="form">

Related

JSF PrimeFaces rendering components

Let's say I have a simple method that, like this:
public String test()
{
return "hello";
}
Now let's say I have the following PrimeFace component:
<p:fieldset styleClass="containers" rendered="#{controller.test()}">
<h2>Testing</h2>
<p:outputLabel for="test" value="Test" />
<p:inputText id="test" />
</p:fieldset>
The method above returns "hello". I would like to dynamically show and hide that fieldSet by comparing the returned value of that method to a field of one of my beans. For instance, on the rendered parameter, I would like to do something like: controller.test() != "some variable" which would return true or false. Am I allow to do that? If not, what is the way of doing it?
Basically the goal is to dynamically show and hide some container by comparing the returned value of a method with a bean property.
Look Like you misunderstood rendered
The rendered Attribute
A component tag uses a Boolean EL expression, along with the rendered
attribute, to determine whether or not the component will be rendered.
If you will check above definition you will know what exactly is the use of this attribute.
More you can see below
The rendered attribute which uses Boolean EL expression indicates
whether a component is currently visible or not. The property is
useful when you want to hide components for specific users or based on
condition. The default value of rendered attribute is true.
<h:outputText value=”mapping” rendered=”Boolean EL expression” />
For example, the commandLink component in the following section of a page is not rendered if the cart contains no items:
<h:commandLink id="check"
...
rendered="#{cart.numberOfItems > 0}">
<h:outputText
value="#{bundle.CartCheck}"/>
</h:commandLink>
With your concrete problem you can do like this
Make a String variable call value
Now create get/set methods for above variable
Now in your test method you can add
public void test(){
value="hello";
}
Bur remember you have call test() method of page load
Now in your Xhtml or Jsf or Jsp page
rendered="#{controller.value != 'hello'}"
Or better way create a Boolean variable and do all the magic of hide and show the component

Pass current selected row of p:dataTable to JavaScript function in p:ajax oncomplete

How can I pass current selected row to JavaScript function in <p:ajax oncomplete>?
<p:dataTable value="#{bolt.sites}" var="bolt" selection="#{bolt.selectedSite}" ...>
<p:ajax event="rowSelect" oncomplete="alert(#{bolt.selectedSite.name});" />
I have tried all: #{bolt.selectedSite.name}, #{bolt.name}.
EL expressions in oncomplete attribute are not evaluated after invoking the action. They are already evaluated while rendering the JavaScript code containing that ajax calling logic.
Your best bet is adding a listener method which adds the name as a callback parameter via RequestContext#addCallbackParam() which will then be available as a property of the implicit args object inside oncomplete context.
<p:ajax ... listener="#{bean.select}" oncomplete="alert(args.name)" />
public void select() {
String name = selectedSite.getName();
RequestContext.getCurrentInstance().addCallbackParam("name", name);
}
Unrelated to the concrete problem, you have a syntax error in your initial JavaScript attempt. The property name "name" suggests that it's a string. In JavaScript, all string values should be quoted. So your fictive solution would be oncomplete="alert('#{bolt.selectedSite.name}');"

Richfaces valueChangeEvent on input not working

I'm trying to use an richfaces inputNumberSlider or inputNumberSpinner.
The problem is I'm not able to update the values in my beans.
Here are the 2 solutions I tried:
1)
<rich:inputNumberSlider value="#{skinningBean.currentSkin.topBar.bannerXOffset}"
valueChangeListener="#{skinningBean.valueBannerXOffSetChangeListener}"
onchange="A4J.findForm(this).submit()">
</rich:inputNumberSlider>
In the bean:
public void valueBannerXOffSetChangeListener(ValueChangeEvent event) {
System.out.println("x value changed");
currentSkin.getTopBar().setBannerXOffset((Integer) event.getNewValue());
}
2)
<rich:inputNumberSpinner value="#{skinningBean.currentSkin.topBar.bannerYOffset}">
<a4j:ajax event="change" render="preview" oncomplete="initSlider()" />
</rich:inputNumberSpinner>
This should just call my setter in the bean. I havw written two setter one which takes a String and one which takes an Integer. None of them is called
Although I need an a4j supprt anyway to rerender my items, a working solution for number 2 would be preferred
Try the following first, once you get it working you can add the oncomplete part:
<rich:inputNumberSpinner value="#{skinningBean.currentSkin.topBar.bannerYOffset}">
<a4j:ajax event="onchange" render="preview" action="#{bean.valueBannerXOffSetChangeListener}" />
</rich:inputNumberSpinner>
Possible you will need to redefine your bean function to not receive parameters.
Reference:
https://community.jboss.org/message/588944#588944

Is it possible to use EL conditional operator in action attribute?

The conditional operator works in many attributes like "rendered" "value" and others.
But it does not work in action? Or am I doing it wrong?
<h:commandLink action="#{true ? bean.methodTrue() : bean.methodFalse()}"/>
Error: javax.el.ELException: Not a Valid Method Expression
(I realized it using primefaces ajax action attribute)
This is not supported. The action attribute is supposed to be a MethodExpression, but the conditional operator makes it a ValueExpression syntax. I don't think this will ever be supported for MethodExpressions in EL.
You have basically 2 options:
Create a single action method which delegates the job.
<h:commandButton ... action="#{bean.method}" />
with
public String method() {
return condition ? methodTrue() : methodFalse();
}
If necessary, pass it in as method argument by #{bean.method(condition)}.
Or, conditionally render 2 buttons.
<h:commandButton ... action="#{bean.methodTrue}" rendered="#{bean.condition}" />
<h:commandButton ... action="#{bean.methodFalse}" rendered="#{not bean.conditon}" />

Reset value to null in primefaces autocomplete event

I have an autocomplete event that fires correctly once a value is selected. I want another event to fire once I erase the value in the textbox and reset the value to null. I was thinking of using the onChange attribute but I was having issues so I reverted back to my original code.
<p:autoComplete id="deviceAuto" dropdown="true" scrollHeight="250"
value="#{summaryReportController.device.nickname}"
forceSelection="true"
completeMethod="#{summaryReportController.deviceComplete}">
<p:ajax event="itemSelect"
listener="#{summaryReportController.handleDeviceSelect}"
update="printThis" />
</p:autoComplete>
public void handleDeviceSelect(SelectEvent event) {
String deviceSelect = event.getComponent().getId();
if (deviceSelect.equalsIgnoreCase("deviceAuto")) {
Device selectedDevice = deviceMgr.getDevicebyNickname(device.getNickname());
setDevice(selectedDevice);
}
updateInterface();
}
When you modify the text content of the AutoComplete textfield, the search method (aka. completeMethod) will be called on the backing bean. You can reset the value to null there if you get an empty string.
Backing Bean
// insert getter and setter for the device property ...
/** Search for devices by name */
public List<String> deviceComplete(String search) {
if (StringUtils.isBlank(search)) {
setDevice(null); // textfield was cleared, reset device value!
return Collections.emptyList();
} else {
// search for devices ...
return deviceNames;
}
}
Note that I used Apache Commons StringUtils.isBlank(String) to check if the string was null or did only contain whitespace characters.
JSF View
In your XHTML file you probably want to listen to any Ajax event to update your view -- or you figure out the event you need (blur, change, whatever) yourself:
<p:autoComplete ...>
<p:ajax event="itemSelect" listener="..." update="..." />
<p:ajax process="#this" update="..." />
</p:autocomplete>
I hope this helps.
An alternative could be something like a "clear" or "reset" button next to the search textfield to make it clear to the user that the value will be cleared.
The default autoComplete minQueryLength attribute equals 1 and your search string will be updated when you deleting it until it has lenght of 1 character.
E.g.:
You entering 'foo' - and this string is provided to search method (updating after entering first character - minQueryLength = 1)
But when you delete search string - it is also updated until it will have length of 1.
Solution:
set attribute minQueryLength="0"
Or:
if you need bigger value add to your autoCompleteMethod(String search) condition:
if (search.length()<={your minQueryLength attribute} ) field = null;
Old question, but I think it worths another view.
The problem with minQueryLenth = 0 or minQueryLenth = 1 is that it can return hundreds of options (and for sure the user won't read all of them to choose one). My solution was as follows.
First of all I need the input to be sent to the server as soon as the user select one of its values (in my use case the user is not allowed to go to next step in a wizard if this value is null or empty). So I put an ajax function triggered in the event of a selected value.
xhtml:
<p:autoComplete
id="someId"
value="#{myViewScopedBean.selectedValue}"
...
...
minQueryLenth="5"
onblur="autoCompleteLostFocus('someId', 'someCommand()')">
<p:ajax
event="itemSelect"
listener="#{myViewScopedBean.newValueSelected}"
process="#this"
update="commandButtonGoToNextStep" />
</p:autoComplete>
<p:remoteCommand
name="someCommand"
actionListener="#{myViewScopedBean.setValueNull}"
update="commandButtonGoToNextStep" />
<p:commandButton
id="commandButtonGoToNextStep"
...
...
disabled="#{myViewScopedBean.selectedValue == null}" />
If the user clean the text, I need to send that value to "myViewScopedBean" and update the component that allows the user to go to the next step. I solved that putting a javascript function that is called when the autocomplete lose focus.
javascript:
function autoCompleteLostFocus(autocompleteId, comand) {
if ($("[id='" + autocompleteId + "_input']").val().trim() == "") {
eval(comando);
}
}
in myViewScopedBean:
public void setValueNull() {
selectedValue = null;
}
I hope it helps. A lot of work, but the behaviour is exactly what I wanted. The reason for the javascript function is that it just send information to the servlet if the value is equals to "", otherwise it does nothing.
From a completely different angle...
Why do you have summaryReportController.device.nickname as a value in autoComplete?
I'd suggest you to use device as a value and specify
var
itemLabel
itemValue
converter
in your autocomplete, while your completeMethod will return list of devices filtered by nickname. Converter is implementation of javax.faces.convert.Converter.
See the POJO case in PF Showcase.

Resources