How to dynamically change panelGroup using selectOneListBox and AJAX - ajax

I want to change the look of the menu based on the selected item.
how to get the value of selectonelistbox using managed bean?
Bean source:
public void selectOneMenuListener(ValueChangeEvent event) {
Object newValue = (String) event.getNewValue();
selectedMenu = newValue.toString();
}
public String getSelectedMenu() {
return selectedMenu;
}
public void setSelectedMenu(String selectedMenu) {
this.selectedMenu = selectedMenu;
}
Page:
<h:panelGroup id="panel">
<h:selectOneListbox id="katProduktu" valueChangeListener="#{produkt_KatBean.selectOneMenuListener}">
<f:selectItems value="#{produkt_KatBean.produkt_KatAllList}"
var="pk" itemLabel="#{pk.symbol}" itemValue="#{pk.id}"/>
<f:ajax render="produktMenu" event="change" execute="#this" />
</h:selectOneListbox>
</h:panelGroup>
<h:panelGroup layout="block" id="produktMenu">
<h:panelGroup rendered="#{produkt_KatBean.selectedMenu==1}">
Menu 1
</h:panelGroup>
<h:panelGroup rendered="#{produkt_KatBean.selectedMenu==2}">
Menu 2
</h:panelGroup>
<h:panelGroup rendered="#{produkt_KatBean.selectedMenu==3}">
Menu 3
</h:panelGroup>
<h:panelGroup rendered="#{produkt_KatBean.selectedMenu==4}">
Manu 4
</h:panelGroup>
</h:panelGroup>
Thanks!

Don't use valueChangeListener. It's the wrong tool for the job. Just bind the property to the value attribute of the menu component and let the rendered attribute intercept on that. This way you don't need a listener at all. Also your rendered comparisons won't work for strings. You should have used == '1' instead of == 1 and so on, but this is plain clumsy, just make it Long (or Integer).
<h:panelGroup id="panel">
<h:selectOneListbox id="katProduktu" value="#{produkt_KatBean.selectedMenu}">
<f:selectItems value="#{produkt_KatBean.produkt_KatAllList}"
var="pk" itemLabel="#{pk.symbol}" itemValue="#{pk.id}"/>
<f:ajax render="produktMenu" />
</h:selectOneListbox>
</h:panelGroup>
<h:panelGroup layout="block" id="produktMenu">
<h:panelGroup rendered="#{produkt_KatBean.selectedMenu==1}">
Menu 1
</h:panelGroup>
<h:panelGroup rendered="#{produkt_KatBean.selectedMenu==2}">
Menu 2
</h:panelGroup>
<h:panelGroup rendered="#{produkt_KatBean.selectedMenu==3}">
Menu 3
</h:panelGroup>
<h:panelGroup rendered="#{produkt_KatBean.selectedMenu==4}">
Manu 4
</h:panelGroup>
</h:panelGroup>
With just
private Long selectedMenu; // Or Integer? Should be the same type as #{pk.id}.
// +getter +setter
(note that I omitted the event and execute attributes of <f:ajax> as they represented the default values already)

Related

JSF page does not retrieve values from back bean

I'm doing a dynamic view according to a dropdown selection:
there's the code:
<h:selectOneMenu value="#{controller.type}" >
<p:ajax listener="#{controller.switchPanels}" update="panels" />
<f:selectItem itemValue="1" itemLabel="option 1" />
<f:selectItem itemValue="2" itemLabel="option 2" />
</h:selectOneMenu>
<h:panelGroup layout="block" id="panels">
<h:panelGroup layout="block" rendered="#{controller.type == '1'}" >
<h:inputText value="#{controller.value}" >
<f:validateRegex pattern="^[0-9a-zA-Z ]*$" />
</h:inputText>
</h:panelGroup>
<h:panelGroup layout="block" rendered="#{controller.type == '2'}" >
Panel 2
</h:panelGroup>
</h:panelGroup>
<h:commandLink action="#{controller.go}">Go</h:commandLink>
The controller:
#ViewScoped
#ManagedBean
public class Controller {
String type = "1";
String value;
// getters and setters
public void switchPanels(AjaxBehaviorEvent event) {
this.value = "";
}
public void go(){
}
...
}
Try this scenario:
- write special characters in the value field
- press Go (causes the validation message to popup)
- try changing the selection and reselect the same panel again
The result is that the field is not cleared even though I clear it in the switchPanels method
Please any explanation would be helpful
Thank you

Primefaces tabview: set the active index on tab change

I've got a tab view that contains two tab.
When I switch from tab 1 to tab 2, I'm calling some code that executes a validation and updates some values. Depending on the result of this validation, I would like to stay on tab 1, or go to tab 2, and refresh the tabs' content.
My tabview:
<h:form id="form">
<p:tabView id="tabview" activeIndex="#{ctrl.idx}" dynamic="true" cache="false">
<p:ajax event="tabChange" listener="#{ctrl.doStuff}" update=":form:tabview"/>
<p:tab title="Tab 1" id="t1">
<h:panelGrid columns="1" cellpadding="10">
<h:outputText value="#{ctrl.s1}"/>
</h:panelGrid>
</p:tab>
<p:tab title="Tab 2" id="t2">
<h:panelGrid columns="1" cellpadding="10">
<h:outputText value="#{ctrl.s2}"/>
</h:panelGrid>
</p:tab>
</p:tabView>
</h:form>
My test code that simly changes the values:
public void doStuff() {
s1 = String.valueOf(Math.random());
s2 = String.valueOf(Math.random());
}
I thought that changing the active tab index in my method would be enough, like that:
public void doStuff() {
// ...
idx = 0;
}
On tabChange event, the method is called but the tabview components goes to the clicked tab, ignoring the idx new value.
I thought adding an update attribute to p:ajax would render the whole tabview but only the tabs and/or the tabs' content is re rendered.
And weirdest of all, if I change update=":form:tabview" to update=":form" or update="#form", I only receive the tab's content in the ajax response -> the component disappears from the page!
My bean is viewscoped, I'm using Primefaces 3.5, JSF 2.1 and Tomcat 7.
Any idea? Thanks.
Try to bind your TabView to server side component instance in your backing bean.
1.Add TabView component instance to your backing bean
org.primefaces.component.tabview.TabView tabview=null;
and coresponding getter and setter
public TabView getTabview() {
return tabview;
}
public void setTabview(TabView tabview) {
this.tabview = tabview;
}
2.Bind server side instance to your TabView
<p:tabView id="tabview" binding=#{yourBean.tabview} dynamic="true" cache="false">
...
</p:tabView>
3.Modify your doStuff() method
public void doStuff() {
// ...
//idx = 0;
tabview.setActiveIndex(0);
}
And it will hopefully do the trick.
i easy fix this with:
public void onSPTabChange(TabChangeEvent event)
{
TabView tabView = (TabView) event.getComponent();
currentData.setSP_Index(tabView.getChildren().indexOf(event.getTab())+1);
}
in currentdata i have property SP_Index with number of tab (first,second....)
<p:tabView id="tabView" styleClass="tabView">
<p:ajax event="tabChange" listener="#{dataAccess.onSPTabChange}" />
....
and add jquery script
<script>
$("#tabView li:nth-child(#{currentData.SP_Index})").click();
</script>
Try to keep your tabview in panelgrid like this way and update this h:panelgrid
h:panelGrid id="mainPanel">
<p:tabView id="tabview" activeIndex="#{ctrl.idx}" dynamic="true" cache="false">
<p:ajax event="tabChange" listener="#{ctrl.doStuff}" update=":form:mainPanel"/>
<p:tab title="Tab 1" id="t1">
<h:panelGrid columns="1" cellpadding="10">
<h:outputText value="#{ctrl.s1}"/>
</h:panelGrid>
</p:tab>
<p:tab title="Tab 2" id="t2">
<h:panelGrid columns="1" cellpadding="10">
<h:outputText value="#{ctrl.s2}"/>
</h:panelGrid>
</p:tab>
</p:tabView>
</h:panelGrid>

Fields are cleared when update p:tabView

I have a popup with three tabs in primefaces tabPanel. In the middle is a table called "composicao", this tab is rendered when user marks checkbox that is located in first tab.
The tables have a lot of inputs, selects and checkboxes that user can fill in any order, so if the user fill all fields and then mark the checkbox, all fields are cleared cause that checkbox update the tabView. I tryied set some fields immediate attribute to true and set p:ajax process attribute to #all, but with this approach nothing happens.
This is the code of tabPanel:
<h:panelGroup id="abasCadastroProduto">
<p:tabView>
<p:tab title="base">
<ui:include src="../../tabs/abaEdicaoBaseProduto.xhtml"/>
</p:tab>
<p:tab id="abaComposicao" title="composicao" rendered="#{produto.composto}">
<ui:include src="../../tabs/abaEdicaoComposicaoProduto.xhtml"/>
</p:tab>
<p:tab
title="tributacao">
<ui:include src="../../tabs/abaEdicaoTributacaoProduto.xhtml"/>
</p:tab>
</p:tabView>
</h:panelGroup>
this is part of the code of first tab:
<h:panelGroup layout="block">
<p:fieldset legend="geral">
<h:panelGroup layout="block">
<h:selectBooleanCheckbox id="produtoAtivoCheck"
value="#{produto.ativo}"/>
<h:outputLabel value="ativo" for="produtoAtivoCheck"/>
<h:selectBooleanCheckbox id="produtoMovimentoCheck"
value="#{produto.movimentaEstoque}"/>
<h:outputLabel value="movimento" for="produtoMovimentoCheck"/>
<!-- THIS IS THE CHECKBOX -->
<h:selectBooleanCheckbox id="produtoCompostoCheck"
value="#{produto.composto}">
<p:ajax event="change" update="abasCadastroProduto" process="#all"/>
</h:selectBooleanCheckbox>
<h:outputLabel value="composto" for="produtoCompostoCheck" />
</h:panelGroup>
.......
<h:panelGroup layout="block">
<h:outputLabel value="descricao"/>
<p:inputText value="#{produto.descricao}" required="true" immediate="true"
requiredMessage="obrigatorio"/>
<h:outputLabel value="complemento"/>
<p:inputText value="#{produto.descricaoComplementar}"/>
</h:panelGroup>
......
</p:fieldset>
</h:panelGroup>
Is there a way I can solve this problem??
I think is unnaceptable to user see fields they spend some time to fill, been cleared when you click in a checkbox...
Solved.
The problem was validation of required fields, so I've created a REQUIRED parameter and set it to false when user clicks checkbox:
<h:selectBooleanCheckbox id="produtoCompostoCheck"
value="#{produto.composto}" styleClass="popup-produto-geral-check">
<f:param name="REQUIRED" value="false"/>
<f:ajax event="change" immediate="true" render="abasCadastroProduto" execute="#form" />
</h:selectBooleanCheckbox>
<h:selectOneMenu value="#{produto.idClasse}" immediate="true"
required="#{param['REQUIRED']}" validatorMessage="#{cadastroMsg['popup.cadastro.produto.base.classe.invalido']}"
requiredMessage="#{cadastroMsg['popup.cadastro.produto.base.classe.obrigatorio']}">
<f:selectItems value="#{selectItemClasse.itens}"/>
<f:ajax event="change" immediate="true" render="selectSubclasse"/>
</h:selectOneMenu>
and I've made submit button set "REQUIRED" parameter to true.
instead of this:
<p:ajax event="change" update="abasCadastroProduto" process="#all"/>
try this:
<p:ajax render="#form" />

Click event on div in JSF2

I have a list represented by a ui:repeat, where each item is a div with some data. What I want is to show the item detail by clicking on the div.
I made it with a button refreshing the form but can't make it work with onclick event on panelGroup.
<h:panelGroup styleClass="container" layout="block">
<ui:repeat value="#{bean.model}" var="item">
<h:panelGroup styleClass="item_data" layout="block">
ID: #{item.id}
<h:commandButton action="#{bean.select}" value="Select item">
<f:param name="itemId" value="#{item.id}"/>
<f:ajax render="#form"></f:ajax>
</h:commandButton>
</h:panelGroup>
<h:panelGroup styleClass="detail"
layout="block"
rendered="#{item eq bean.selected}">
value: #{bean.selected.value}
</h:panelGroup>
</ui:repeat>
</h:panelGroup>
If I understand you correctly, you just want to show the detail section without re-rendering the whole form? If so, then wrap it in a component which is always rendered in the HTML DOM tree, give it an id and refer it instead:
<ui:repeat value="#{bean.model}" var="item">
<h:panelGroup styleClass="item_data" layout="block">
ID: #{item.id}
<h:commandButton action="#{bean.select}" value="Select item">
<f:param name="itemId" value="#{item.id}"/>
<f:ajax render="detail" />
</h:commandButton>
</h:panelGroup>
<h:panelGroup id="detail">
<h:panelGroup styleClass="detail"
layout="block"
rendered="#{item eq bean.selected}">
value: #{bean.selected.value}
</h:panelGroup>
</h:panelGroup>
</ui:repeat>
See also:
Communication in JSF 2.0 - Ajax rendering of content which is by itself conditionally rendered
Update: as per the comments, you actually want to invoke JSF ajax action by <h:panelGroup onclick> no, that's not possible as it doesn't support onclick attribute. You could use a <div> with jsf.ajax.request() function, but cleaner would be to use a <h:commandLink> with CSS display: block so that it spans the entire div.
<h:panelGroup styleClass="item_data" layout="block">
<h:commandLink action="#{bean.select}" value="ID: #{item.id}" styleclass="detailLink">
<f:param name="itemId" value="#{item.id}"/>
<f:ajax render="detail" />
</h:commandLink>
</h:panelGroup>
with e.g.
.detailLink {
display: block;
color: black;
text-decoration: none;
}

JSF - Create a Dynamic Menu by using AJAX & selectOneListbox

What I'd like to do is simple to explain :
bean
#ManagedBean
#ViewScoped
public class Articles {
private String selectedMenu;
#PostConstruct
public void init() {
if(selectedMenu==null || selectedMenu.trim().isEmpty()) {
this.selectedMenu="0";
}
}
public String getSelectedMenu() { return selectedMenu; }
public void setSelectedMenu(String selectedMenu) { this.selectedMenu = selectedMenu; }
}
page
<h:selectOneListbox onchange="..?? ajax call that render on loadMenu and pass the value of the focused listbox to Articles Bean" id="category" size="0" >
<f:selectItem itemLabel="first" itemValue="0" />
<f:selectItem itemLabel="second" itemValue="1" />
<f:selectItem itemLabel="third" itemValue="2" />
</h:selectOneListbox>
<h:panelGroup layout="block" id="loadMenu">
<h:panelGroup rendered="#{articles.selectedMenu=='0'}">
MENU 0
</h:panelGroup>
<h:panelGroup rendered="#{articles.selectedMenu=='1'}">
MENU 1
</h:panelGroup>
<h:panelGroup rendered="#{articles.selectedMenu=='2'}">
MENU 2
</h:panelGroup>
</h:panelGroup>
When I change the value of the listbox, the menu should change dinamically (by calling some function on the server). I think that the code above expresses what I'm looking for.
I must know how call it using the onchange option. Is it possible?
Cheers
UPDATE
<h:panelGroup layout="block">
<h:selectOneListbox styleClass="article_combo" size="0" id="selectedMenu" >
<f:selectItem itemLabel="first" itemValue="0" />
<f:selectItem itemLabel="second" itemValue="1" />
<f:selectItem itemLabel="third" itemValue="2" />
<f:ajax event="change" execute="#this" render="loadMenu" />
</h:selectOneListbox>
</h:panelGroup>
<h:panelGroup layout="block" id="loadMenu">
<h:panelGroup rendered="#{articles.selectedMenu=='0'}">
MENU 0
</h:panelGroup>
<h:panelGroup rendered="#{articles.selectedMenu=='1'}">
MENU 1
</h:panelGroup>
<h:panelGroup rendered="#{articles.selectedMenu=='2'}">
MENU 2
</h:panelGroup>
</h:panelGroup>
You can use the ajax support built in to JSF 2 to achieve this. To do this nest an f:ajax tag in your h:selectOneListbox tag. The f:ajax tag should look like:
<f:ajax render="loadMenu" execute="#this" />
This should process the changed value in your list box, and re-render the panelGroup.
for further details, see:
http://mkblog.exadel.com/2010/04/learning-jsf-2-ajax-in-jsf-using-fajax-tag/

Resources