Primefaces dataTable single selection validation - validation

I can validate a p:selectOneMenu like this:
<p:selectOneMenu id="eventTimezoneDropdown"
value="#{myBean.eventTimeZone}"
required="true"
requiredMessage="The TimeZone must be specified."
effect="none">
<f:selectItems value="#{myBean.timeZoneItems}"/>
</p:selectOneMenu>
Conceptually speaking, using a p:dataTable with single row selection will achieve the same goal - it allows you to select one row using a selection attribute instead of value attribute and using value attribute instead of <f:selectItems>.
<p:dataTable id="ActivitiesTable" var="row"
value="#{myBean.rows}"
selection="#{myBean.selectedRow}"
rowKey="#{row.activityId}">
<p:column selectionMode="single"/>
...
</p:dataTable>
However I don't see any validation options (e.g. a required attribute) on the p:dataTable.
Is there a way or workaround to have a required selection validation on a p:dataTable similar to the required attribute on p:selectOneMenu?
Environment: Primefaces 5.3, JSF 2.2.8-14, Tomcat 7.0.68.

what i know in primefaces there are not this functionality in datatable, but you can play with your code,
i suggest that you can do the same event in your ManagedBean, so you can check if a row is selected or not, if yes then ok else you can create a simple message, that notifie the user that the selection of a row is required like that:
public void requiredSelect() {
if (myObject == null) {
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(
FacesMessage.SEVERITY_ERROR, "Error", "My object is required!"));
}
}

Another way to work around this issue is by using a hidden input field, bound to the same value which gets updated on row select.
<p:dataTable id="ActivitiesTable" var="row"
value="#{myBean.rows}"
selection="#{myBean.selectedRow}"
rowKey="#{row.activityId}">
<p:ajax event="rowSelectRadio" update="#parent:hiddenTimezoneInput"
<p:column selectionMode="single"/>
...
</p:dataTable>
<h:inputHidden id="hiddenTimezoneInput" value="#{myBean.selectedRow}"
required="true" requiredMessage="The TimeZone must be specified."/>
This way, you can add regular validators on the inputHidden (such as required) and have it processed on form submit.

Related

JSF form validation skip specific validator for second submit when user wants to override

I am validating a user entered account number using two validators, one for basic standard format, and the other that validates the account number against values stored in a database. The database of valid account numbers may not always be up to date so I want to allow the user to override and submit their entered account number but only after the database validation has failed. I always want to validate its standard format 8 characters with no spaces.
<h:form id="formId">
<p:panelGrid>
<p:row>
<p:column>
<p:outputLabel value="Account : " for="acct" />
</p:column>
<p:column>
<p:selectOneMenu id="acct" value="#{bean.acct.acctNum}" effect="fold" editable="true" validator="acctLengthAndSpaceValidator" required="true" requiredMessage="Required">
<f:selectItems value="#{bean.mySavedAccounts}" var="acct"
itemLabel="#{acct.acctNumber} itemValue="#{acct.acctNumber}" />
<o:validator validatorId="accountDatabaseValidator" disabled="#{bean.skipDbValidation}" />
</p:selectOneMenu>
</p:column>
<p:column>
<p:messages for="acct" showDetail="true" skipDetailIfEqualsSummary="true" />
</p:column>
</p:row>
</p:panelGrid>
<br />
<p:selectBooleanCheckbox rendered="#{facesContext.validationFailed}" value="#{bean.skipDbValidation}" itemLabel="I know this account is really valid, please skip validation and let me submit!">
<p:ajax update="#this" listener="#{bean.testListener()}" />
</p:selectBooleanCheckbox>
<p:commandButton value="Submit" action="#{bean.submit()}" update="formId"/>
</h:form>
The checkbox does appear after the form is initially submitted and has any validation failure (I will figure out how to isolate to just the failed accountDatabaseValidator). But then when I select the checkbox, and submit again, both validators are still fired. I added the ajax listener to debug, and it isn't firing and the boolean value skipDbValidation is still false.
Perhaps my approach is not correct in achieving my concrete goal of validating against the database but then giving the user the option of skipping the db validation after initial failure.
EDIT
if i remove rendered="#{facesContext.validationFailed}" from the checkbox and have it visible all the time, the boolean skipDbValidation will get set to true if the checkbox is checked and then on subsequent submit, the skipDbValidation is ignored as expected. But I do not want the checkbox allowing the user to bypass visible at first. Only after validation fails.
The technical explanation that this doesn't work is that the rendered attribute is re-evaluated during processing the form submit. At this point the faces context is not validationFailed anymore (it was only validationFailed during the previous request) and thus the component is not rendered anymore and then the component's submitted value won't be applied. This matches #6 of commandButton/commandLink/ajax action/listener method not invoked or input value not set/updated.
Your work around by rendering it client-side rather than server-side is acceptable. But I gather that you wanted to show it only when the specific validator has been invoked. There are at least 2 ways to achieve this:
Check UIInput#isValid() of the input component of interest. You can achieve that by binding the component to the view (not to the bean!) via component's binding attribute so you can reference it elsewhere in the same view.
<p:selectOneMenu binding="#{acct}" ...>
...
</p:selectOneMenu>
...
<p:selectBooleanCheckbox styleClass="#{acct.valid ? 'ui-helper-hidden' : ''}" ...>
...
</p:selectBooleanCheckbox>
Note that I took the opportunity to reuse the PrimeFaces-provided style class.
Or, make the validator a view scoped bean and reference it via <o:validator binding> instead.
#Named
#ViewScoped
public class AccountDatabaseValidator implements Validator, Serializable {
private boolean validationFailed;
#Override
public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {
// ...
validationFailed = !isValid(value);
if (validationFailed) {
throw new ValidatorException(createError("Invalid value"));
}
}
public boolean isValidationFailed() {
return validationFailed;
}
}
<p:selectOneMenu ...>
<o:validator binding="#{accountDatabaseValidator}" ... />
</p:selectOneMenu>
...
<p:selectBooleanCheckbox rendered="#{accountDatabaseValidator.validationFailed}" ...>
...
</p:selectBooleanCheckbox>
My work around to get the checkbox to programmatically display and so the checkbox would function was to hide and display using CSS instead of the render attribute.
style="#{facesContext.validationFailed ? 'Display: inline' : 'Display: none;'}"
<p:selectBooleanCheckbox style="#{facesContext.validationFailed ? 'Display: inline' : 'Display: none;'}" value="#{bean.skipDbValidation}" itemLabel="I know this account is really valid, please skip validation and let me submit!">
<p:ajax update="#this" />
</p:selectBooleanCheckbox>
But I still can't figure out how to display the checkbox for a specific validation failure.
I will post another question for that
EDIT
Here is how I ended up displaying the checkbox only after the Invalid Account validation failure.
<p:selectBooleanCheckbox style="#{facesContext.messageList.stream()
.anyMatch(v -> v.summary == 'Invalid Account') or
bean.skipDbValidation ? 'Display: inline' : 'Display: none;'}"
value="#{bean.skipDbValidation}" itemLabel="I know this account is really valid, please skip validation and let me submit!">
<p:ajax update="#this" />
</p:selectBooleanCheckbox>

SelectOneMenu set to null when updating p:panelGrid

I am having a problem, I am firing a ajax event in a selectOneMenu like this: the first one does not fire any event
<p:selectOneMenu id="IdSelectOne" value="#{MB.myentity.myValue}" converter="myConverter1">
.....
</p:selectOneMenu>
<p:selectOneMenu id="IdSelectTwo" converter="myConverter2">
<p:ajax event="change" process="#this" partialSubmit="true"
listener="#{MB.ChangeOption}" update="creatPanel" >
</p:ajax>
</p:selectOneMenu>
The problem is that when the ajax event updates the panel, the first SelectOneMenu sets tu null, i can't use #form because it validates all fields and never do what I need which is show a field based on the selection of the second SelectOneMenu, is there a way to avoid this problem to happend?
This is my backing bean:
public void ChangeOption(AjaxBehaviorEvent event){
.....
}
I solved it by updating just the element I needed and not the complete panel, Thanks

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));
}
}

Validation for selected row in JSF h:datatable

I am having a tough time trying to find a solution to the following design related to h:dataTable.
I have certain number of rows predisplayed. The first column is only checkboxes. The rest of the columns are disabled by default. On selecting a checkbox the elements in the corresponding rows get enabled. On submit of the for the values in the enabled row have to be validated on the server side. I am able to validate for invalid inputs but am not finding a method to use required="true" conditionally. Or any other method. Could anyone please help me on this.
Thanks
Barun
I'm guessing you have a bean that looks something like this...
public class SomeBean {
boolean selected = false;
String someProperty;
...
}
If you have a controller for those beans your markup would look something like this...
<h:dataTable value="#{SomeController.someBeans}" var="someBean">
<h:column>
<f:facet name="header">Select</f:facet>
<h:selectBooleanCheckbox value="#{someBean.selected}"/>
</h:column>
<h:column>
<f:facet name="header">Input</f:facet>
<h:inputText value="#{someBean.someproperty}" required="#{someBean.selected}"/>
</h:column>
</h:dataTable>
You should have a method like:
public boolean isSelected(){
return selected;
}

Resources