Duplicate validation in two selectonemenu in primefaces - validation

I have two p:selectOneMenu in a page, both have the same content, the user has to choose two different items, the user cannot choose same item in both selectOneMenu. How do I implement this validation ? My current code is something like this :
<p:selectOneMenu id="itemOne"
value="#{backingBean.itemOne}"
required="true" label="Item One:" requiredMessage="Item one is required!">
<f:selectItem itemLabel="Select One" itemValue="" />
<f:selectItems value="#{backingBean.itemList}" var="item"
itemLabel="#{item.QLabel}" itemValue="#{item.QLabel}" />
</p:selectOneMenu>
<p:selectOneMenu id="itemTwo"
value="#{backingBean.itemTwo}"
required="true" label="Item Two:" requiredMessage="Item two is required!">
<f:selectItem itemLabel="Select One" itemValue="" />
<f:selectItems value="#{backingBean.itemList}" var="item"
itemLabel="#{item.QLabel}" itemValue="#{item.QLabel}" />
</p:selectOneMenu>
The first thing came to my mind was to attach a listener in both menus with 'onchange' event, remove already selected item and update the other menu but this seems overkill for such simple task. Is there any other way I can do this ?

Related

Partial Rendering of Form fields with ajax valueChange event in jsf

<h:form id="newStudentForm">
<h:outputLabel value="Student" for="studentId" />
<p:selectOneMenu value="#{myBean.studentId}" id="studentId">
<f:selectItems value="#{myBean.studentList}" var="student"
itemLabel="#{student.name}" itemValue="#{student.id}" />
</p:selectOneMenu>
<h:outputLabel value="Address" for="addressId" />
<p:selectOneMenu value="#{myBean.addressId}" id="addressId">
<f:selectItems value="#{myBean.addressList}" var="address"
itemLabel="#{address.name}" itemValue="#{address.id}" />
</p:selectOneMenu>
<h:outputLabel value="Address" for="addressId" />
<p:selectOneMenu value="#{myBean.subjectId}" id="subjectId">
<f:selectItems value="#{myBean.subjectList}" var="subject"
itemLabel="#{subject.name}" itemValue="#{subject.id}" />
<a4j:ajax event="valueChange"
render="newStudentForm"
listener="#{myBean.checkSubject}"
execute="#this"/>
</p:selectOneMenu>
<h:outputLabel value="Price" for="priceId" rendered="#{myBean.checkSubject}" />
<p:selectOneMenu value="#{myBean.priceId}" id="priceId"
rendered="#{myBean.checkSubject}">
<f:selectItem itemValue="#{null}" itemLabel="" />
<f:selectItems value="#{myBean.priceList}" var="price"
itemLabel="#{price.name}" itemValue="#{price.id}"/>
</p:selectOneMenu>
</h:form>
I am trying to make a field dynamic i.e field Price, when i am selecting a value from subject, the price field is dependent on that value. Everything is working fine in this code except that when i am rendering the form, the values that i enter in other fields(like address) before selecting subject is being overridden by the initial values. So how should i refactor this ajax event call so that the values do not get overridden.
The checkSubject function is returning true or false based on subject selected.

Force user to select different values in multiple h:selectOneMenu showing same lists

I am relatively new to JSF and Primefaces. I have a page in which I have three selectOneMenu displaying the same set of values from a map. I would like to make sure that the user selects different values for the three drop downs. I have achieved this by writing a custom validator. But the validator works only if I click the submit page. I want to have an ajax call which would show an error message for drop down 2 as soon as the user selects the same value as drop down 1.Also the same case for drop down 3.Here is my code snippet:
user.xhtml
<h:outputLabel for="Question1" value="#{msg['account.question1']}"/>
<h:message styleClass="validation-error" for="Question1"/>
<h:selectOneMenu id="Question1" required="true" value="#{account.question1}" class="smallTxt">
<f:selectItems value="#{controller.questionMap}" />
<f:validator validatorId="com.validator.QuestionsValidator"></f:validator>
</h:selectOneMenu>
<h:outputLabel for="Answer1" value="#{msg['account.answer1']}"/>
<h:message styleClass="validation-error" for="Answer1"/>
<h:inputText id="Answer1" required="true" value="#{account.answer1}" />
<h:outputLabel for="Question2" value="#{msg['account.question2']}"/>
<h:message styleClass="validation-error" for="Question2"/>
<h:selectOneMenu id="Question2" required="true" value="#{account.question2}" class="smallTxt">
<f:selectItems value="#{controller.questionMap}" />
</h:selectOneMenu>
<h:outputLabel for="Answer2" value="#{msg['account.answer2']}"/>
<h:message styleClass="validation-error" for="Answer2"/>
<h:inputText id="Answer2" required="true" value="#{account.answer2}" />
<h:outputLabel for="Question3" value="#{msg['account.question3']}"/>
<h:message styleClass="validation-error" for="Question3"/>
<h:selectOneMenu id="Question3" required="true" value="#{account.question3}" class="smallTxt">
<f:selectItems value="#{controller.questionMap}" />
</h:selectOneMenu>
<h:outputLabel for="Answer3" value="#{msg['account.answer3']}"/>
<h:message styleClass="validation-error" for="Answer3"/>
<h:inputText id="Answer3" required="true" value="#{account.answer3}" />
I am using JSF 2 and Primefaces 5.2.
Thanks in advance
If you want to execute your validator on an AJAX call, you have to add <f:ajax /> to your <h:selectOneMenu>
<h:selectOneMenu id="Question1" required="true" value="#{account.question1}" class="smallTxt">
<f:selectItems value="#{controller.questionMap}" />
<f:validator validatorId="com.validator.QuestionsValidator"></f:validator>
<f:ajax />
</h:selectOneMenu>
Side question: You state, that you use Primefaces 5.2, but you use JSF standard components (<h:selectOneMenu> instead of <p:selectOneMenu>). Is that on purpose?
You can apply listener on selectonemenu.linke this:
<p:selectOneMenu id="country" value="#{dropdownView.country}" style="width:150px">
<p:ajax listener="#{dropdownView.onCountryChange}" update="city" />
<f:selectItem itemLabel="Select Country" itemValue="" noSelectionOption="true" />
<f:selectItems value="#{dropdownView.countries}" />
</p:selectOneMenu>
And then in this oncountrychange() function you will get the values of all the three select items and compare them.

PrimesFaces - Render a panelGroup after onChange

I have a selectOneMenu with two items and a panelGroup.
When item 1 is selected I want to show the panelGroup and when item 2 is selected hide it.
I try to do it with the onchange event but I don't know how show/hide the panelGroup. Maybe using the panelGroup ID ?
<p:selectOneMenu id="list" value="#{myBean.list}" onchange="???" >
<f:selectItem itemLabel="Item 1" itemValue="Item 1" />
<f:selectItem itemLabel="Item 2" itemValue="Item 2" />
</p:selectOneMenu>
<h:panelGroup id="myPanelGroup">
...
</h:panelGroup>
the change="" will either give u access to a EL Listener or a javascript, which has no update component to it. You're best off adding a ajax call inside the selectOneMenu.
e.g.
<p:selectOneMenu id="list" value="#{myBean.list}">
<f:selectItem itemLabel="Item 1" itemValue="Item 1" />
<f:selectItem itemLabel="Item 2" itemValue="Item 2" />
<p:ajax event="change" process="#this" update="myPanelGroup" />
</p:selectOneMenu>
<h:panelGroup id="myPanelGroup" rendered="#{myBean.list == '1'">
...
</h:panelGroup>
(you need to have rendered on it to ensure it's only shown if your value is 1 (not 2 etc). Although this is the AJAX solution, you could do it using jQuery by binding a change listener to the selectOneMnu 'list' - on change, run your javascript and show/hide the panelgroup div (means u dont need the rendered etc)..
Example:
$("#list").change(function(event){
//get value here and show/hide div using javascript/css what ever you prefer
});
you can use <p:remoteCommand> tag to update you form. And use rendered to show/hide your panel.
see below code and it is working on my side and much easier.
<p:remoteCommand id="remotecommand" name="updatePanel"
update="#form"></p:remoteCommand>
<p:selectOneMenu id="list" value="#{myBean.list}" onchange="updatePanel()" >
<f:selectItem itemLabel="Item 1" itemValue="Item 1" />
<f:selectItem itemLabel="Item 2" itemValue="Item 2" />
</p:selectOneMenu>
<h:panelGroup id="myPanelGroup" rendered="#{myBean.list eq 'Item 1'}">
...
</h:panelGroup>
When the value of list is Item 1 on that time show the panel otherwise it is hide
Rendering content on demand is a common practice in jsf. You should also rethink the use of a two choices selectOneMenu. You have to wrap the content in a panelGroup element and set the inner element to be rendered like this:
<p:selectBooleanCheckbox id="cboOverview" value="#{ctrlBean.bValue}">
<p:ajax event="change" update="outputOverviewWrapper" />
</p:inputSwitch>
<h:panelGroup id="outputOverviewWrapper">
<h:panelGroup id="toggleOverview" rendered="#{!ctrlBean.bValue}">
...
</h:panelGroup>
</h:panelGroup>
If you want to stick with the selectOneMenu you should also use a valueChangeListener to set the rendering attribute properly.
Reference is here.

Update another component based on a change in the selectonemenu value

We are using JSF 1.2 for our project. Requirement is to update another selectonemenu options based on a value change in the current selectonemenu.
Based on select1 option, select2 needs to be updated.
<h:selectOneMenu id="select1" value="#{subscription.subscriptions}" onchange="javascriptMethod()">
<f:selectItem id="item1" itemLabel="News" itemValue="1" />
<f:selectItem id="item2" itemLabel="Sports" itemValue="2" />
</h:selectOneMenu>
<h:panelGroup id="panel2">
<h:selectOneMenu id="select2" value="#{subscription.subscriptions2}">
<f:selectItem id="item1" itemLabel="News" itemValue="1" />
<f:selectItem id="item2" itemLabel="Sports" itemValue="2" />
</h:selectOneMenu>
</h:panelGroup>
You can use ajax support like this
<h:selectOneMenu id="select1" value="#{subscription.subscriptions}" >
<f:selectItem id="item1" itemLabel="News" itemValue="1" />
<f:selectItem id="item2" itemLabel="Sports" itemValue="2" />
</h:selectOneMenu>
Jsf 1.2 doesn't have ajax support the only thing you can do is full page reload which happens on a command button.
I presumed you are using richfaces as a third party for ajax and rich ui components.
Hope this helps.
If you are using primefaces then you can replace tag with like this
<p:ajax event="onchange" update="select2" action="if you want to anything in
backend"/>
If you want to do by javascript then have a hidden h:commandButton and put code in your
javascriptMethod() method like this
document.getElementById("myHiddenButtonId").click();

Hide and show components depending on h:selectOneMenu value

I have a page with a <h:selectOneMenu> and I want to show some fields or others depending on the chosen value of the menu. Is this possible and if so, how?
<h:selectOneMenu id="productname" value="#{product.productname}" required="true">
<f:selectItem itemLabel="select" itemValue="null" />
<f:selectItem itemLabel="Detetgent" itemValue="Detergent"/>
<f:selectItem itemLabel="Dishwash" itemValue="Dishwash" />
<f:selectItem itemLabel="Powder" itemValue="Powder" />
<f:selectItem itemLabel="Liquid" itemValue="Liquid" />
</h:selectOneMenu>
<h:panelGroup rendered="Detergernt">
<p>This will be shown if the selected item Detergent.</p>
</h:panelGroup>
<h:panelGroup >
<p>This will be shown if the selected item Dishwash.</p>
</h:panelGroup>
<h:panelGroup >
<p>This will be shown if the selected item equal to powder.</p>
</h:panelGroup>
<h:panelGroup >
<p>This will be shown if the selected item equals to Liquid.</p>
</h:panelGroup>
You just need to check in the rendered attribute if #{product.productname} returns the desired value. In order to update all those components, you should add an <f:ajax> to the menu which updates a common parent component —which is always rendered— of all conditionally rendered components.
<h:selectOneMenu id="productname" value="#{product.productname}" required="true">
<f:selectItem itemLabel="select" itemValue="null" />
<f:selectItem itemLabel="Detetgent" itemValue="Detergent"/>
<f:selectItem itemLabel="Dishwash" itemValue="Dishwash" />
<f:selectItem itemLabel="Powder" itemValue="Powder" />
<f:selectItem itemLabel="Liquid" itemValue="Liquid" />
<f:ajax render="groups" />
</h:selectOneMenu>
<h:panelGroup id="groups">
<h:panelGroup rendered="#{product.productname == 'Detergent'}">
<p>This will be shown if the selected item Detergent.</p>
</h:panelGroup>
<h:panelGroup rendered="#{product.productname == 'Dishwash'}">
<p>This will be shown if the selected item Dishwash.</p>
</h:panelGroup>
<h:panelGroup rendered="#{product.productname == 'Powder'}">
<p>This will be shown if the selected item equal to Powder.</p>
</h:panelGroup>
<h:panelGroup rendered="#{product.productname == 'Liquid'}">
<p>This will be shown if the selected item equals to Liquid.</p>
</h:panelGroup>
</h:panelGroup>
See also:
Conditionally displaying JSF components
Why do I need to nest a component with rendered="#{some}" in another component when I want to ajax-update it?
<h:selectOneMenu id="productname" value="#{product.productname}" required="true">
<f:selectItem itemLabel="select" itemValue="null" />
<f:selectItem itemLabel="Detetgent" itemValue="Detergent"/>
<f:selectItem itemLabel="Dishwash" itemValue="Dishwash" />
<f:selectItem itemLabel="Powder" itemValue="Powder" />
<f:selectItem itemLabel="Liquid" itemValue="Liquid" />
<p:ajax event="onselect" update="selectedOp" listener="#{product.updateSelectedValue}" />
</h:selectOneMenu>
<h:panelGroup rendered="{product.updateSelectedValue ne null}" id="selectedOp">
<p>This will be show selected value</p>
#{product.updateSelectedValue}
</h:panelGroup>
This is how you can display the selected value from drop down on the page. I assume that you are using PrimeFaces, so using an ajax event tag <p:ajax> inside <h:selectOneMenu >. Also adding the condition on <h:panelGroup rendered="{product.updateSelectedValue ne null}">, so that it will be displayed when selected value is other than null.
Yea, you can achieve this . Please do paste your page , so that it is easy for me to explain on the page itself.
The idea is to use an <a4j:outputPanel> as a container and <h:panelGrourp layout="block" rendered="#{}"> as a wrappper for the fields which are need to hidden.
The selected value of selectOneMenu will be used in the rendered attribute of <h:panelGroup>.

Resources