PrimesFaces - Render a panelGroup after onChange - events

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.

Related

Composite Component - AJAX clientBehaviour

We have build a component that consists of a TextInput and Select Box. So that the selection can be made either via the drop down list or by typing in the value into the text field. When a selection is made the Input Box is automatically filled with the key and if the key is entered the correct item in the selection box is displayed.
<h:panelGroup rendered="#{cc.attrs.rendered}">
<div id="#{cc.clientId}" class="abc-select #{cc.attrs.styleClass}" >
<h:inputText id="input" disabled="#{cc.attrs.disabled}"
value="#{cc.attrs.value}">
<a4j:ajax event="change" render="select" />
</h:inputText>
<rich:select disabled="#{cc.attrs.disabled}"
id="select" value="#{cc.attrs.value}"
listWidth="#{cc.attrs.listWidth}"
converter="#{cc.attrs.converter}">
<f:selectItems value="#{cc.attrs.items}" var="item"
itemValue="#{item}" itemLabel="#{item.name}" />
<a4j:ajax event="selectitem" render="input" oncomplete="setFocusOnInputField();" />
</rich:select>
</div>
</h:panelGroup>
However when we pass in an <a4j:ajax event="change" ... /> with an onChange event to render a component external element. It only works when the selection is made via the drop down menu.
<abc:myComponent id="idMC"
value="#{bean.value}"
items="#{bean.itemList}"
converter="#{itemConverter}">
<a4j:ajax event="change" render="idA idB idC" />
</kfn:select>
So far I figured out that it must have to do with the fact that the inputText already has an a4j element listing for change <a4j:ajax event="change" render="select" />.
When I change the ajax element in the inputText element to use <f:ajax .. /> instead it works fine.
Can someone explain why this is the case and is there a better solution?

Duplicate validation in two selectonemenu in primefaces

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 ?

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>.

h:inputText is not ajax-rendered on change of h:selectOneMenu

I have this code which is used to select how many rows to display in jsf table:
<!-- Set rows per page -->
<h:outputLabel for="rowsPerPage" value="Rows per page" />
<h:inputText id="rowsPerPage" value="#{AccountsController.rowsPerPage}" size="3" maxlength="3" />
<h:commandButton styleClass="bimage" value="Set" action="#{AccountsController.pageFirst}" >
<f:ajax render="#form" execute="#form"></f:ajax>
</h:commandButton>
<h:message for="rowsPerPage" errorStyle="color: red;" />
I want to edit the code this way: I want to replace the code with h:selectOneManu and option to insert custom value with AJAX support:
<h:selectOneMenu id="setrows" value="#{AccountsController.rowsPerPage}" converter="javax.faces.Integer" maxlength="3">
<f:selectItem itemValue="10" itemLabel="10" />
<f:selectItem itemValue="50" itemLabel="50" />
<f:selectItem itemValue="100" itemLabel="100" />
<f:selectItem itemValue="500" itemLabel="500" />
<f:selectItem itemValue="332" itemLabel="Custom" />
<f:ajax render="customrowperpage" />
</h:selectOneMenu>
<h:inputText id="customrowperpage" value="#{AccountsController.rowsPerPage}" rendered="#{AccountsController.rowsPerPage == '332'}" required="true" />
But for some reason the code is not working. Can you help me to find the problem. Also I want to update AJAX functionality when I select number from the h:selectOneMenu list AJAX call to update the form.
There are 2 problems.
First, as JavaScript runs in the client side, you can't ajax-update a JSF component which isn't rendered to the client side. There's then simply nothing in the HTML DOM tree which JavaScript can select, manipulate and replace. You should instead ajax-update a JSF component which is always rendered to the client side.
<h:panelGroup id="customrowperpage">
<h:inputText value="#{AccountsController.rowsPerPage}" required="true"
rendered="#{AccountsController.rowsPerPage == '332'}" />
</h:panelGroup>
See also Why do I need to nest a component with rendered="#{some}" in another component when I want to ajax-update it?
Second, an Integer never equals a String. You're in the rendered attribute testing Integer rowsPerPage against String '332'. Remove those singlequotes to make it a fullworthy number.
<h:panelGroup id="customrowperpage">
<h:inputText value="#{AccountsController.rowsPerPage}" required="true"
rendered="#{AccountsController.rowsPerPage == 332}" />
</h:panelGroup>

Ajax update part of panelGrid

I have a panel grid with 2 columns, the first containing a label and the second a component.
The listener backingBean.onFunktionChange sets the value of backingBean.functionGraduand to true. So the label and the menue for the degree are rendered in this case.
The problem is that if I first select a city in the menu for city and then change the value in the menu "function", the whole panel is updated and thus the city menu is reset.
However, in case of function change I want to to keep the preselected city.
If I wrap the label and component for function and degree in a panelGroup with id=panelFunction lets say and only update this panel, destroys the two column layout.
Is there any possibility to only update a part of the panelGrid without affecting the layout of the panelGrid?
<h:panelGrid columns="2" id="panel">
<label>#{function}</label>
<p:selectOneMenu id="menuFunction" value="#{...}" >
<p:ajax event="change" process="menuFunction"
update="panel"
listener="#{backingBean.onFunctionChange}" />
<f:selectItems .../>
</p:selectOneMenu>
<h:outputLabel id="labelDegree" for="menuDegree"
value="#{msgs.degree}"
rendered="#{backingBean.functionGraduand}" />
<p:selectOneMenu id="menuDegree" value="#{...}" rendered="#{backingBean.functionGraduand}">
<f:selectItems .../>
</p:selectOneMenu>
<label class="required">#{msgs.city}</label>
<p:selectOneMenu value="#{...}" id ="city">
<f:selectItems .../>
</p:selectOneMenu>
</h:panelGrid>
I solved this by processing the whole panel in the ajax request:
...
<p:ajax event="change" process="panel"
update="panel"
listener="#{backingBean.onFunctionChange}" />
...

Resources