Input text validation based on drop-down list selection - validation

How can I validate an input text box based on a selection from the drop-down list?

You could pass the selected value of the dropdown as an attribute of the input component so that the validator can grab it.
E.g.
<h:selectOneMenu binding="#{menu}" value="#{bean.item}">
<f:selectItems value="#{bean.items}" />
</h:selectOneMenu>
<h:inputText value="#{bean.input}">
<f:attribute name="item" value="#{menu.value}" />
<f:validator validatorId="inputValidator" />
</h:inputText>
with
#FacesValidator("inputValidator")
public class InputValidator implements Validator {
#Override
public void validate(FacesContext context, UIComponent component, Object value) {
Object item = component.getAttributes().get("item");
// ...
}
}
Note that the ordering of the components matters. JSF processes UIInput components in the order they appear in the view. If the dropdown component is placed after the input text component, then you need to pass #{menu.submittedValue} as attribute, but at that point the value is not converted yet. You could if necessary workaround with a <h:inputHidden> which is placed after the both components and put the validator in there.

Related

Execute Backing Bean Action on p:selectOneRadio

I'm using a radio component on which, when selecting an item I want to execute an action on backing bean (not navigate to an outcome page, but to perform some action and then update current page via Ajax). Problem is I can't get the backing bean value change listener action to execute
<h:form id="one-radio">
<p:selectOneRadio layout="grid"
valueChangeListener="#{myBean.selectRadioItem}" >
<p:ajax process="#this" update="#form" />
<f:selectItems value="#{myBean.radioOptions}" var="radio"
itemLabel="#{radio.name}" itemValue="#{radio.id}" >
</f:selectItems>
</p:selectOneRadio>
</h:form>
and the backing bean method...
public void selectRadioItem(ValueChangeEvent event) {
String[] selectedItems = (String[]) event.getNewValue();
//more...
}
is there something wrong in the code which I'm missing? I've used this same structure for select many check box which is working...
Rodrigo, there's a difference between valueChangeListener and a simple method call via ajax.
Check this answer by BalusC about the difference between valueChangeListener and <f:ajax>
To solve your problem, you could use the listener property of <p:ajax>.
OneRadio component is used to receive only one value, if you want to select a list of values, use SelectOneMenu
Try to do the following:
<p:selectOneRadio layout="grid" value="#{myBean.radioValue}">
<p:ajax process="#this" update="#form" listener="#{myBean.selectRadioItem}"/>
<f:selectItems value="#{myBean.radioOptions}" var="radio"
itemLabel="#{radio.name}" itemValue="#{radio.id}" >
</f:selectItems>
</p:selectOneRadio>
In the backbean, you can remove the event parameter, because the value of the OneRadio component now is a property, which I named as radioValue
String radioValue;
...
public void selectRadioItem() {
String selectedItem = this.radioValue;
//more...
}

issue with ajax in primefaces "selectOneMenu"

index.xhtml
<p:selectOneMenu id="d2" value="#{mainManageBean.areaSelected}" >
<f:selectItem itemValue="" itemLabel="Select one" />
<f:selectItems value="#{mainManageBean.areaList}" var="area"
itemValue="#{area.id}" itemLabel="#{area.name}"/>
<p:ajax event="valueChange" listener="#{mainManageBean.changeAreaSelect()}" update="hi" />
</p:selectOneMenu>
When i have value set like this "mainManageBean.areaSelected" where areaSelected is entity from database
private Area areaSelected;
the ajax event dont work,
but when i change it to something like this "mainManageBean.s1menu" where this "s1menu" is just a normal String ajax event work fine.
What is the reason of that and how to fix it?
Edit
this is my buged converter:
#FacesConverter
public class areaConverter implements Converter{
#Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
// here i have problem value is id of entity and have no idea how to get this entity form this id
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
// works fine value = Area entity
#Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
if (value == null || value.equals("")) {
return "";
} else {
return String.valueOf(((Area) value).getId());
}
}
}
Have problem with getAsObject, i have this value as id but cant get entity from it. Normaly i would use AreaFacade.find(id) but i cant use there #EJB to get it.
First of all, your <f:selectItem itemValue> is wrong. It should represent exactly the same type as <p:selectOneMenu value>, which is thus Area. Replace itemValue="#{area.id}" by itemValue="#{area}". You indeed need a Converter for this.
As to your problem with the converter,
Have problem with getAsObject, i have this value as id but cant get entity from it. Normaly i would use AreaFacade.find(id) but i cant use there #EJB to get it.
you have 2 options:
Make it a #ManagedBean #RequestScoped instead of #FacesConverter and reference it as converter="#{areaConverter}" instead of converter="areaConverter".
Install OmniFaces >= 1.6. It adds full transparent support for #EJB inside #FacesConverter without any additional configuration or annotations.
If you go the OmniFaces path anyway, then you could also just throw away your custom converter altogether and go for its builtin SelectItems(Index)Converter without the need to create any custom converter for itemValue="#{area}".
<p:selectOneMenu ... converter="omnifaces.SelectItemsConverter">
See also:
CDI Injection into a FacesConverter
You are trying to set an Entity with value of ID, I assume Integer or String? The reason why ajax does not fire is because event="valueChange" does not occur. If you tried to submit this form without ajax you would get a sweet ClassCastException. As I mentioned in my comment and Makky in his answer, change itemValue to:
<p:selectOneMenu id="d2" value="#{mainManageBean.areaSelected}" >
<f:selectItem itemValue="#{null}" itemLabel="Select one" />
<f:selectItems value="#{mainManageBean.areaList}" var="area"
itemValue="#{area}" itemLabel="#{area.name}"/>
<p:ajax listener="#{mainManageBean.changeAreaSelect()}" update="hi" process="#this />
</p:selectOneMenu>
As per comment from Kuba
<f:selectItems value="#{mainManageBean.areaList}" var="area"
itemValue="#{area.id}" itemLabel="#{area.name}"/>
change itemValue as
<f:selectItems value="#{mainManageBean.areaList}" var="area"
itemValue="#{area}" itemLabel="#{area.name}"/>
Update:
The other thing it could be the converter. My suggestion is to use the SelectItemsConverter from Onmnifaces.
Omnifaces select item converter

selectOneMenu ajax events

I am using an editable primefaces selectOneMenu to display some values. If the user selects an item from the List a textarea should be updated. However, if the user types something in the selectOneMenu, the textarea should not be updated.
I thought I could work this with ajax event out. However, I don't know which event I can use here. I only know the valueChange event. Are there any other events, like onSelect or onKeyUp?
Here is my code:
<p:selectOneMenu id="betreff" style="width: 470px !important;"
editable="true" value="#{post.aktNachricht.subject}">
<p:ajax event="valueChange" update="msgtext"
listener="#{post.subjectSelectionChanged}" />
<f:selectItems value="#{post.subjectList}" />
</p:selectOneMenu>
<p:inputTextarea style="width:550px;" rows="15" id="msgtext"
value="#{post.aktNachricht.text}" />
The PrimeFaces ajax events sometimes are very poorly documented, so in most cases you must go to the source code and check yourself.
p:selectOneMenu supports change event:
<p:selectOneMenu ..>
<p:ajax event="change" update="msgtext"
listener="#{post.subjectSelectionChanged}" />
<!--...-->
</p:selectOneMenu>
which triggers listener with AjaxBehaviorEvent as argument in signature:
public void subjectSelectionChanged(final AjaxBehaviorEvent event) {...}
I'd rather use more convenient itemSelect event. With this event you can use org.primefaces.event.SelectEvent objects in your listener.
<p:selectOneMenu ...>
<p:ajax event="itemSelect"
update="messages"
listener="#{beanMB.onItemSelectedListener}"/>
</p:selectOneMenu>
With such listener:
public void onItemSelectedListener(SelectEvent event){
MyItem selectedItem = (MyItem) event.getObject();
//do something with selected value
}
Be carefull that the page does not contain any empty component which has "required" attribute as "true" before your selectOneMenu component running.
If you use a component such as
<p:inputText label="Nm:" id="id_name" value="#{ myHelper.name}" required="true"/>
then,
<p:selectOneMenu .....></p:selectOneMenu>
and forget to fill the required component, ajax listener of selectoneMenu cannot be executed.
You could check whether the value of your selectOneMenu component belongs to the list of subjects.
Namely:
public void subjectSelectionChanged() {
// Cancel if subject is manually written
if (!subjectList.contains(aktNachricht.subject)) { return; }
// Write your code here in case the user selected (or wrote) an item of the list
// ....
}
Supposedly subjectList is a collection type, like ArrayList. Of course here your code will run in case the user writes an item of your selectOneMenu list.

How to skip validation for ajax call?

I have an h:inputText, h:selectonemenu and commandbuton. Inputtext is mandatory field and I have defined it as immediate="true". Then I when I click the button I want to pass current value of selectonemenu to managed bean. But its passig null. How can I manage this validation so that it allows me to get the value of selectOneMenu in Managed bean..
My code is..
<h:inputText id="inputSome" required="true" requiredMessage="Pls enter something"/>
<h:message for="inputSome"></h:message>
<h:selectOneMenu id="recepients" value="#{controller.selected}" immediate="true">
<f:selectItem itemLabel="Select" itemValue=""/>
<f:selectItems value="#{controller.tempNameList1}"></f:selectItems>
</h:selectOneMenu>
<p:commandButton value="Add" action="#{controller.submit}"
immediate="true"/>
When you put immediate=true in the commandButton, then Invoke Application phase is directly executed skipping the phases after (and including) validations. So "applying model values" phase is also skipped and the properties of managed bean are remained uninitialized. This causes you passing null for the value of selectOneMenu. The solution is, you have to retrieve the value for selected property of the controller manually, like bellow:
Map<String, String> paramMap = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap();
for (String key : paramMap.keySet()) {
if (key.contains("recepients")) {
selected = Integer.parseInt(paramMap.get(key));
}
}

Validate input as required only if certain command button is pressed

I have specific use case for JSF validation. For example I have an inputText field:
<p:inputText id="input" required="#{myBean.required}" value="#{myBean.value}" maxlength="20" disabled="#{myBean.disabled}">
<p:ajax event="blur" process="#this" update="name" listener="#{myBean.listener}"/>
</p:inputText>
Value of input is number (in some cases it can also be a string, because this is part of composite component, but problem is better described if we assume this is a number). This input is part of the form, at the end of form I have submit button:
<p:commandButton value="Save" actionListener="#{myBean.save}"/>
What are my requests:
When submit button is pressed all validation should be processed and this is OK, this works fine.
When blur event is fired on input field if field is not empty a number validation should be processed, and this is also OK. At the end I update field with id name with some value.
Now I have a problem. My third request is when input is empty validation on input should not be processed. This is special case in which I will clear field with id name. This is also case when i remove text which is already entered in input, remove focus from component (press TAB for example) and in that case AJAX request should also be processed and name input will also be cleared.
How I can disable validation of this input field in case when it is empty, and just for this ajax event?
Let the input's required attribute check if the save button is pressed or not (which can be identified by the presence of its client ID in the request parameter map).
<h:form>
<p:inputText ... required="#{not empty param[save.clientId] and myBean.required}" />
<p:commandButton binding="#{save}" ... />
</h:form>
(note: do not bind it to a bean property! the code is as-is)
This way it would only evaluate true when the save button is actually pressed.
Or, if you have problems with binding and/or don't have a problem hardcoding the button's client ID:
<h:form id="formId">
<p:inputText ... required="#{not empty param['formId:buttonId'] and myBean.required}" />
<p:commandButton id="buttonId" ... />
</h:form>
Just remove the required attribute as you accept the input if the input is empty. Then write a custom validator which accepts only empty input or numerical input.
<p:inputText id="input" value="#{myBean.value}" maxlength="20" disabled="#{myBean.disabled}" validator="customerNumericInputValidator"> <p:ajax event="blur" process="#this" update="name" listener="#{myBean.listener}"/> </p:inputText>
public class customerNumericInputValidator implements Validator {
#Override
public void validate(FacesContext facesContext, UIComponent uIComponent,
Object object) throws ValidatorException {
String number = (String) object;
number = Strings.nullToEmpty(number).trim();
//if the request is a full request then number can not be empty
if(!FacesContext.getCurrentInstance().isPostback() && Strings.isNullOrEmpty(number))
{
FacesMessage message = new FacesMessage();
message.setSummary(Messages.getMessage("error empty value"));
message.setSeverity(FacesMessage.SEVERITY_ERROR);
throw new ValidatorException(message);
}
if(!Strings.isNullOrEmpty(number))
{
if(!isNumber(number))
{
FacesMessage message = new FacesMessage();
message.setSummary(Messages.getMessage("error not numerical value"));
message.setSeverity(FacesMessage.SEVERITY_ERROR);
throw new ValidatorException(message);
}
}
}
}

Resources