I'm implementing a PrimeFaces picklist in a dialog. Everytime the dialog is shown the contents of the target of the picklist should change depending on a list entry shown before. Before I open the dialog I fill the target of the picklist in ProdukteBean.onEditProdukt(..) with the appropriate values. Unfortunately these target values do not show up in the target container. Here are the relevant code pieces:
list.xhtml:
<p:commandLink id="editButton" update=":dialogForm:editDialogPanel" title="Edit"
oncomplete="produktDialog.show();"
process="#this" partialSubmit="true"
action="#{produkteBean.onEditProdukt}">
<h:outputText value="Bearbeiten" />
<f:setPropertyActionListener value="#{p}" target="#{produkteBean.produkt}" />
</p:commandLink>
dialog.xhtml:
<!-- ... -->
<p:dialog id="dialog" header="Produkt-Details" widgetVar="produktDialog" appendToBody="true" showEffect="explode" hideEffect="explode" modal="true" width="500">
<p:messages id="msgs"/>
<h:form id="dialogForm">
<!-- ... -->
<p:pickList id="produkteDatenList" var="proddat" value="#{produkteBean.datenList}"
itemLabel="#{proddat.bezeichnung}" itemValue="#{proddat}"
converter="produktDatConverter"/>
<!-- ... -->
</h:form>
</p:dialog>
ProdukteBean.java:
#Named("produkteBean")
#ViewScoped // #SessionScoped // #ViewScoped
public class ProdukteBean implements Serializable {
#Inject #Transient private ProdukteService produkteService;
#Inject #Transient private DatenService datenService;
#Inject()
private ProdukteDatenBean produkteDatenBean;
private DualListModel<Dat> datenList = new DualListModel<Dat>();
private Dat dat = null;
public ProdukteBean() {
}
#PostConstruct
private void init() {
getAll();
}
private void getAll() {
logger.debug("getAll()");
getAllProdukte();
getAllDaten();
}
private void getAllDaten() {
logger.debug("getAllDaten()");
List<Dat> source = new ArrayList<Dat>();
source.addAll(datenService.list());
List<Dat> target = new ArrayList<Dat>();
if (produkt.getDaten() != null) {
logger.debug("adding " + produkt.getDaten().size() + " daten to produkt " + produkt.getName());
target.addAll(produkt.getDaten());
}
DualListModel<Dat> datenList = new DualListModel<Dat>();
datenList.setSource(source);
datenList.setTarget(target);
setDatenList(datenList);
}
public List<Produkt> getAllProdukte() {
logger.debug("getAllProdukte()");
return produkteService.list();
}
public void onEditProdukt() {
onEditProdukt(null);
}
public void onEditProdukt(ActionEvent actionEvent) {
logger.debug("onEditProdukt: " + ReflectionToStringBuilder.toString(produkt));
if (produkt != null) {
setSelectedEinheit(produkt.getEinheit());
getAllDaten();
}
FacesMessage msg = new FacesMessage("Produkt ausgewählt", produkt.getName());
FacesContext.getCurrentInstance().addMessage(null, msg);
}
/**
* #return the einheitList
*/
public List<Einheit> getEinheitList() {
if (einheitList == null) {
einheitList = produkteService.getEinheiten();
}
return einheitList;
}
}
ProduktDatConverter.java:
#FacesConverter(forClass=Dat.class,value="produktDatConverter")
#ViewScoped
public class ProduktDatConverter implements Converter {
#Inject
#Transient DatenService datenService;
#Transient
protected final Logger logger = Logger.getLogger(getClass().getName());
// gets never called (of course)
public Object getAsObject(FacesContext arg0, UIComponent arg1, String str) {
logger.debug("getAsObject(): " + str);
return null;
}
public String getAsString(FacesContext arg0, UIComponent arg1, Object object) {
if (object instanceof Dat) {
// logger.debug(" returning id " + String.valueOf(((Dat) object).getId()));
return Long.toString(((Dat) object).getId());
}
return null;
}
}
Any ideas? Many thanks in advance!
You are using #ViewScoped along CDI Managed Bean. Change it to JSF Managed Bean. Better, use CODI instead
Also see:
View Scope in CDI Weld
CDI missing #ViewScoped and #FlashScoped
I suppose it's converter + injection problem. Please, click here and refer to the BalusC answer. You can also try to replace:
#FacesConverter(forClass=Dat.class,value="produktDatConverter")
#ViewScoped
with
#ManagedBean
#RequestScoped
and call the converter like this:
converter="#{produktDatConverter}"
Related
I am try to develop a web application where I need the Conversation scope to carry on with the same String value in multiple xhtml pages with Primefaces 3.5.
When I begin the conversation with conversation.begin(), it throws null pointer exception with conversation being as null.
I know I can't create a instance of Conversation using 'new'. But I can't figure out where am I going wrong and why is it coming to be null.
Please guide.
Snippet of the xhtml where the bean method is called:
<p:column style="text-align: left" headerText="Deal ID"
width="30">
<p:commandLink value="#{selectedDealBean.getDealID()}"
action="#{SearchBean.action(selectedDealBean.getDealID())}"
process="#this" >
</p:commandLink>
</p:column>
Snippet of bean:
#Named()
#ManagedBean
#ConversationScoped
public class SearchBean implements Serializable {
#Inject
private Conversation conversation;
private DealBean selectedDealBean;
private String selectedID;
private SearchObject searchObj = new SearchObject();
public void start() {
this.conversation.begin();
}
public void end() {
conversation.end();
}
public void submit() {
System.out.println(selectedDealBean);
}
public String action(String selectedID) {
String actionstatus = null;
setSelectedID(selectedID);
actionstatus = "/common/dealDisplay.xhtml?faces-redirect=true" ;
start();
return actionstatus;
}
public String onFinish() {
end();
return "/common/create.xhtml";
}
}
You're mixing annotations. Since you're using CDI you should remove #ManagedBean annotation which is possibly the reason why your injection isn't working.
I filled my rightList of the PickList with Objects from a web service, but when i select some elements, i want to get these elements in myManagedBean, because i'll affect them to an Object.
JSF :
<h:form>
<rich:panel>
<h:panelGrid columns="2" styleClass="criteresSaisie"
rowClasses="critereLigne" columnClasses="titreColonne,">
<h:outputLabel for="libelleCoplement" value=" "
size="20" />
<rich:pickList d="libelleCoplement" sourceCaption="Compléments"
targetCaption="Compléments sélectionnés"
value="#{listeCmpltDispoModel.listeCmpltSelect}" size="15"
addText=">" addAllText=">>" removeText="<"
removeAllText="<<" listWidth="270px" listHeight="110px"
orderable="true">
<f:converter converterId="cmpltsTitresConcerter" />
<f:selectItems value="#{listeCmpltDispoModel.listeCmpltDispo}"
var="liste" itemLabel="#{liste.libelleComplement}"
itemValue="#{liste.cdComplement}"/>
</rich:pickList>
</h:panelGrid>
<h:panelGroup>
<div align="right">
<h:panelGrid columns="8">
<h:commandButton value="Valider"
action="#{saisieCmpltsTitreCtrl.valider}" />
</h:panelGrid>
</div>
</h:panelGroup>
</rich:panel>
</h:form>
The bean :
#ManagedBean(name = "listeCmpltDispoModel")
#SessionScoped
public class ListeCmpltDispoModel implements Serializable {
private static final long serialVersionUID = 1L;
private Long cdComplement;
private String libelleComplement;
private int nbCompl;
private List<ComplementsDispoSortieDTO> listeCmpltDispo ;
private List<ComplementsDispoSortieDTO> listeCmpltSelect ;
public ListeCmpltDispoModel() {
}
public Long getCodeComplement() {
return cdComplement;
}
public void setCodeComplement(Long cdComplement) {
this.cdComplement = cdComplement;
}
public String getLibelleComplement1() {
return libelleComplement;
}
public void setLibelleComplement1(String libelleCoplement) {
this.libelleComplement = libelleCoplement;
}
public Long getCdComplement() {
return cdComplement;
}
public void setCdComplement(Long cdComplement) {
this.cdComplement = cdComplement;
}
public String getLibelleComplement() {
return libelleComplement;
}
public void setLibelleComplement(String libelleComplement) {
this.libelleComplement = libelleComplement;
}
public List<ComplementsDispoSortieDTO> getListeCmpltDispo() {
return listeCmpltDispo;
}
public void setListeCmpltDispo(List<ComplementsDispoSortieDTO> listeCmpltDispo) {
this.listeCmpltDispo = listeCmpltDispo;
}
public int getNbCompl() {
return nbCompl;
}
public void setNbCompl(int nbCompl) {
this.nbCompl = nbCompl;
}
public List<ComplementsDispoSortieDTO> getListeCmpltSelect() {
return listeCmpltSelect;
}
public void setListeCmpltSelect(List<ComplementsDispoSortieDTO> listeCmpltSelect) {
this.listeCmpltSelect = listeCmpltSelect;
}
}
Converter :
#FacesConverter(value="cmpltsTitresConcerter")
public class CmpltsTitresConcerter implements Converter {
#SuppressWarnings("null")
public Object getAsObject(FacesContext context, UIComponent component,
String value){
ComplementsDispoSortieDTO cmpltSelect = null;
cmpltSelect.setCdComplement(Long.parseLong(value));
return cmpltSelect;
}
public String getAsString(FacesContext arg0, UIComponent arg1, Object obj) {
return String.valueOf(((ComplementsDispoSortieDTO) obj).getCdComplement());
}
}
Any help is greatly apprectiated!
Roughtly you need 3 things :
Custom converter for your object (Object to String, String to Object)
Getter/Setter with the List of your Objects choices
Getter/Setter with the List of your Objects selected
Everything is perfectly described here : RichFaces Showcase - pickList
EDIT :
Adding this should fix your problem :
<rich:pickList ...>
<f:converter converterId="cmpltsTitresConcerter" />
</rich:pickList>
also the converter property in <f:selectItems /> is not valid : f:selectItems
EDIT :
You should modify your converter like that to remove converting exceptions :
#FacesConverter(value="cmpltsTitresConcerter")
public class CmpltsTitresConcerter implements Converter
{
public Object getAsObject(FacesContext context, UIComponent component, String value)
{
ComplementsDispoSortieDTO cmpltSelect = null;
if(value != null)
{
cmpltSelect = new ComplementsDispoSortieDTO();
cmpltSelect.setCdComplement(Long.parseLong(value));
}
return cmpltSelect;
}
public String getAsString(FacesContext arg0, UIComponent arg1, Object obj)
{
String result = null;
if(obj != null)
{
result = String.valueOf(((ComplementsDispoSortieDTO) obj).getCdComplement());
}
return result;
}
}
Your selected objects are bound to the value attribute which must have a getter and setter.
I'm trying to implement on JSF data table a binding to a backed bean value with a nested data table with a binding to a value of the current data row, see this code:
<h:form prependId="false">
<h:dataTable binding="#{tableBean.mainDataTable}" var="row" >
<h:column>
<h:dataTable binding="#{row.nestedDataTable}" />
</h:column>
</h:dataTable>
</h:form>
And these are the backed beans and data:
#ManagedBean
#SessionScoped
public class TableBean implements Serializable{
private HtmlDataTable mainDataTable;
private List<TableBeanData> tableBeanDataLst;
public TableBean() {
tableBeanDataLst = new ArrayList<TableBeanData>();
DataModel<TableBeanData> mainDataModel =new ListDataModel<TableBeanData>(tableBeanDataLst);
mainDataTable = new HtmlDataTable();
mainDataTable.setValue(mainDataModel);
}
public HtmlDataTable getMainDataTable() {
return mainDataTable;
}
public void setMainDataTable(HtmlDataTable mainDataTable) {
this.mainDataTable = mainDataTable;
}
public List<TableBeanData> getTableBeanDataLst() {
return tableBeanDataLst;
}
public void setTableBeanDataLst(List<TableBeanData> tableBeanDataLst) {
this.tableBeanDataLst = tableBeanDataLst;
}
}
public class TableBeanData implements Serializable{
private HtmlDataTable nestedDataTable;
public TableBeanData (){
nestedDataTable = new HtmlDataTable();
}
public HtmlDataTable getNestedDataTable() {
return nestedDataTable;
}
public void setNestedDataTable(HtmlDataTable nestedDataTable) {
this.nestedDataTable = nestedDataTable;
}
}
But I get a property not found exception:
/index.xhtml #17,69 binding="#{row.nestedDataTable}": Target Unreachable, indentified 'row' resolved to null
I don't understand well, because I'm Initializing the datatables in the constructors.
How can I resolve this type of error to allow this configuration of table, nested table and data bindings?
i' m developing my first jsf2 richfaces application , and now i am faced with the following problem :
i have the following menù
<rich:panelMenu >
<rich:panelMenuGroup >
<rich:panelMenuItem label="Users" name="Users " />
<rich:panelMenuItem label="Orders" name="Orders" />
</rich:panelMenuGroup>
</rich:panelMenu>
I want that when click on the panelMenuItem is created a new tab and within of this new tab must insert a table that contains all users of the my application
i saw a few example of this type
<rich:tabPanel switchType="client" id="tabPanel">
<c:forEach items="#{handlerTab.tabsName}" var="tabName">
<rich:tab name = ... >
</rich:tab>
</c:foreach>
but don't know as insert a table in my new tab
how can i do?
tanks for your reply, but i don't want declare all tabs in the view , i want add and remove tab dynamically , now i have managed to do this
<rich:panelMenu >
<rich:panelMenuGroup >
<rich:panelMenuItem label="Users" name="Users" action="#{tabsBean.createTabs()}" render="tabs" />
<rich:panelMenuItem label="Orders" name="Orders" action="#{tabsBean.createTabs()}" render="tabs" />
</rich:panelMenuGroup>
<h:panelGrid id="tabs" binding="#{tabsBean.panelGrid}"/>
then i have a bean that manage the tabs
#ManagedBean
#SessionScoped
public class TabsBean {
private HtmlPanelGrid panelGrid;
private Integer numOfTabs;
#PostConstruct
public void init(){numOfTabs=1;}
public Integer getNumOfTabs() {
return numOfTabs;
}
public void setNumOfTabs(Integer numOfTabs) {
this.numOfTabs = numOfTabs;
}
public TabsBean() {
}
public HtmlPanelGrid getPanelGrid() {
return panelGrid;
}
public void setPanelGrid(HtmlPanelGrid panelGrid) {
this.panelGrid = panelGrid;
}
public void createTabs (){
FacesContext context = FacesContext.getCurrentInstance();
Application application = context.getApplication();
UITabPanel tabPanel = (UITabPanel)application.createComponent(UITabPanel.COMPONENT_TYPE);
tabPanel.setSwitchType(SwitchType.ajax);
for (int i=0; i<numOfTabs; i++){
UITab tab = new UITab();
tab = (UITab)application.createComponent(UITab.COMPONENT_TYPE);
tab.setName("User Count "+i);
tabPanel.getChildren().add(tab);
}
numOfTabs++;
panelGrid.getChildren().clear();
panelGrid.getChildren().add(tabPanel);
}
}
now my problem is that i must add of components a this tabs (datatable that contains all user , form for insert a user and other)
how can i do?
If you want the menu to open tabs with specific content it's better if you pre-create the tab and hide it, showing it (rendering) on request. To create the Users do the following:
Create a User class (if you don't have one)
public class User {
private String name;
private String country;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
}
Create a UserTab managed bean
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
#ManagedBean
#ViewScoped
public class UserTab implements Serializable {
private List<User> users;
private boolean rendered;
public UserTab() {
//Initialize list
users = new ArrayList();
//Initialize rendered attribute
rendered = false;
//Replace this for your User data retrieving method
createDummyUsers();
}
private void createDummyUsers() {
User user = new User();
user.setName("John Doe");
user.setCountry("USA");
users.add(user);
user = new User();
user.setName("Bill Doe");
user.setCountry("Canada");
users.add(user);
user = new User();
user.setName("Winston Doe");
user.setCountry("England");
users.add(user);
}
public void showTab() {
rendered = true;
}
public void hideTab() {
rendered = false;
}
public List<User> getUsers() {
return users;
}
public void setUsers(List<User> users) {
this.users = users;
}
public boolean isRendered() {
return rendered;
}
public void setRendered(boolean rendered) {
this.rendered = rendered;
}
}
Create a tab handler:
import java.io.Serializable;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
#ManagedBean
#ViewScoped
public class TabHandler implements Serializable {
private String activeTab;
public TabHandler() {
activeTab = "none";
}
public String getActiveTab() {
return activeTab;
}
public void setActiveTab(String activeTab) {
this.activeTab = activeTab;
}
}
Create the view
<h:body>
<h:form>
<rich:panelMenu >
<rich:panelMenuGroup >
<rich:panelMenuItem label="Users" name="Users"
actionListener="#{userTab.showTab()}">
<f:ajax event="select"
execute="#this"
render="tabPanel"
listener="#{tabHandler.setActiveTab('usersTab')}"/>
</rich:panelMenuItem>
<rich:panelMenuItem label="Orders" name="Orders" />
</rich:panelMenuGroup>
</rich:panelMenu>
<rich:tabPanel id="tabPanel"
switchType="client"
activeItem="#{tabHandler.activeTab}">
<rich:tab id="mainTab">
</rich:tab>
<rich:tab id="usersTab"
rendered="#{userTab.rendered}">
<f:facet name="header">
<h:outputLabel value="Users"/>
<h:commandLink value=" X" actionListener="#{userTab.hideTab()}"/>
</f:facet>
<rich:dataTable value="#{userTab.users}"
var="user">
<rich:column>
#{user.name}
</rich:column>
<rich:column>
#{user.country}
</rich:column>
</rich:dataTable>
</rich:tab>
</rich:tabPanel>
</h:form>
</h:body>
Do the same steps and add the required tags for the Order class.
See:
RichFaces dynamic TabPanel
c:forEach is not an option if you want to add the tabs by click.
What you want is to add components dynamically:
How to dynamically add JSF components
Dynamically added input field in ui:repeat is not processed during form submit
How to Dynamically adding fields in JSF?
I'm still trying to program an app with jsf2, ejb3.1, cdi and glassfish.
I have a form which have a selectOneMenu
<h:form prependId="false">
...
<f:validateBean>
...
<h:selectOneMenu value="#{bottleManagedBean.selectProducer}" id="selectproducerb"
validatorMessage="#{messages.bottleaddinvalideproducer}" immediate="true">
<f:converter binding="#{producerConverter}"/>
<f:selectItems value="#{bottleManagedBean.producerItems}" />
</h:selectOneMenu>
...
The of the selectItems component are well showned but when I submit the form the value of bottleManagedBean.selectProducer is always null.
My formbean
#Named("bottleManagedBean")
#RequestScoped
public class BottleManagedBean {
....
private List<Producer> producers;
public List<Producer> getProducers() {
if (producers == null) {
setProducers(producerService.list(Producer.class));
}
return producers;
}
public void setProducers(List<Producer> producers) {
this.producers = producers;
}
private Producer selectProducer;
public Producer getSelectProducer() {
return selectProducer;
}
private List<SelectItem> producerItems;
public List<SelectItem> getProducerItems() {
if (producerItems == null) {
producerItems = new ArrayList<SelectItem>();
for (Producer current : getProducers()) {
producerItems.add(new SelectItem(current.getId(), current.getName()));
}
}
return producerItems;
}
public void setProducerItems(List<SelectItem> producerItems) {
this.producerItems = producerItems;
}
...
The converter
#Named("producerConverter")
public class ProducerConverter implements Converter {
#Inject
BusinessService<Producer> service;
private static Logger trace = Logger.getLogger(ProducerConverter.class.getCanonicalName());
#Override
public Object getAsObject(FacesContext fc, UIComponent uic, String id) {
try {
return service.findByID(Producer.class, Integer.parseInt(id));
} catch (NumberFormatException e) {
e.printStackTrace();
throw new ConverterException(e);
}
}
#Override
public String getAsString(FacesContext fc, UIComponent uic, Object o) {
String asString = null;
if (o != null) {
asString = String.valueOf(o);
}
return asString;
}
}
I tried to debug the app .When I submit the form , the application never goes to the setter.
I also tried to add a valuechangelistener and my app never called this method.
Finally, I tried to submit an integer (eg. the id of my bean) and the value is well filled when I submit.1
So,... what's wrong ?
Thanks in advance for your help
here is how you should use the valuechangelistener properly in jsf2
Add <f:ajax listener="#{bottleManagedBean.selectProducer}" /> to your <h:selectOneMenu
Like this:
<h:selectOneMenu value="#{bottleManagedBean.selectProducerValueChange}" id="selectproducerb"
validatorMessage="#{messages.bottleaddinvalideproducer}">
<f:ajax listener="#{bottleManagedBean.selectProducerValueChange}" />
<f:converter binding="#{producerConverter}"/>
<f:selectItems value="#{bottleManagedBean.producerItems}" />
</h:selectOneMenu>
and implement the selectProducerValueChange in your bean...