I've got simple composite component which has to render h:selectManyListbox with h:messages associated with it. The problem is with using faces converter class. It seems to be not working with it (only if used in component code).
Composite component code :
<?xml version="1.0" encoding="UTF-8"?>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:composite="http://java.sun.com/jsf/composite">
<!-- INTERFACE -->
<composite:interface>
<composite:attribute name="description" required="true" />
<composite:attribute name="fieldValue" required="true" />
<composite:attribute name="idc" required="true" />
<composite:attribute name="size" required="true" />
</composite:interface>
<!-- IMPLEMENTATION -->
<composite:implementation>
<tr>
<td nowrap="nowrap">
<h:outputText value="#{cc.attrs.description}" />
</td>
<td>
<h:selectManyListbox
id="#{cc.attrs.idc}"
size="#{cc.attrs.size}"
value="#{cc.attrs.fieldValue}">
<composite:insertChildren />
</h:selectManyListbox>
</td>
<td>
<h:message for="#{cc.attrs.idc}" />
</td>
</tr>
</composite:implementation>
</html>
When I use it on sample.xhtml page (as shown below), I get 'Validation Error: Value is not valid'.
.....
But when on the same page I put code like:
<tr>
<td><h:outputText value="Plugins" /></td>
<td>
<h:selectManyListbox
id="plugins"
value="#{bean.currentPlugins}"
size="6">
<f:selectItems value="#{bean.availablePlugins}" />
</h:selectManyListbox>
</td>
<td><h:message for="plugins" /></td>
</tr>
everything goes fine.
The managed bean 'bean' class is
#ManagedBean
#SessionScoped
public class Bean extends GenericManagedBean
implements Serializable {
ElementClass[] currentPlugins;
// getter & setter for currentPlugins
// ...
public List<ElementClass> getAvailablePlugins() {
// .. some code
return list;
}
}
and ElementClass is
public class ElementClass extends GenericEntity implements Serializable {
private static final long serialVersionUID = 9159873495276902436L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "ID")
private Integer id;
// other fields
// ...
// getters & setters
// ...
#Override
public int hashCode() {
int hash = 0;
hash += (id != null ? id.hashCode() : 0);
return hash;
}
#Override
public boolean equals(Object object) {
if (!(object instanceof ElementClass)) {
return false;
}
ElementClass other = (ElementClass) object;
if ((this.id == null && other.id != null)
|| (this.id != null && !this.id.equals(other.id))) {
return false;
}
return true;
}
}
For the ElementClass I've got converter class
#FacesConverter(forClass = ElementClass.class)
public class ElementClassConverter implements Converter {
#Override
public Object getAsObject(FacesContext fc, UIComponent uiComponent,
String elemId) {
if (!StringUtils.isEmpty(elemId)) {
// this code gets ElementClass object entity from database
ApplicationBean applicationBean = JSFHelper
.findBean("applicationBean");
return applicationBean.getService()
.findElementClassById(
Integer.parseInt(elemId));
} else {
return null;
}
}
#Override
public String getAsString(FacesContext fc, UIComponent uiComponent,
Object elem) {
return elem != null ? ((ElementClass ) elem).getId()
.toString() : "";
}
}
And standard question: what am I doing wrong? I assume this is my lack of knowledge rather than jsf implemenation bug. I use JBoss 7.1.1 AS and everything, what is bundled with it + RichFaces 4.
Related
I created a managedBean & .xhtml page.It works fine on jsf 2.1 but not working on jsf 2.2 .Showing error Target Unreachable, identifier 'regionMaster' resolved to null
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:prime="http://primefaces.org/ui">
<head>
</head>
<ui:composition>
<h:form id="regionMaster" name="regionMaster">
<div id="region">
<table align="center">
<tr>
<td><prime:panel header="Region">
<prime:messages autoUpdate="true" />
<prime:panelGrid style="margin-top:20px">
<prime:row>
<prime:column>
<h:outputLabel for="txtRegionID" value="RegionID" />
</prime:column>
<prime:column colspan="3">
<prime:inputText id="txtRegionID" value="#{regionMaster.regionId}"
label="Region ID" required="true" />
</prime:column>
<prime:column>
<!-- <h:commandButton id="openPopUp" value="..."
target="RegionList.xhtml"
onclick="window.open('RegionList.xhtml','childWindow','status=no,toolbar=no,location=no,menubar=no,resizable = no,width=1008,height=390,scrollbars,left=100,top=50');"
action="#{regionList.xhtml}" />-->
<!-- <prime:commandButton value="View" icon="ui-icon-extlink"
actionListener="#{regionMaster.regionList}" validateClient="false" immediate="true" />-->
<prime:dialog id="basicDialog" header="Basic Dialog"
widgetVar="dlg1">
<h:outputText value="Resistance to PrimeFaces is futile!" />
</prime:dialog>
<prime:commandButton id="basic" value="Basic"
onclick="PF('dlg1').show();" type="button" />
</prime:column>
</prime:row>
<prime:row>
<prime:column>
<h:outputLabel for="txtRegionName" value="RegionName" />
</prime:column>
<prime:column colspan="3">
<prime:inputText id="txtRegionName" value="#{regionMaster.regionName}"
label="Region Name" required="true" />
</prime:column>
</prime:row>
<prime:row>
<prime:column>
</prime:column>
<prime:column colspan="1">
<prime:commandButton action="#{regionMaster.save}"
value="save" />
</prime:column>
<prime:column colspan="1">
<prime:commandButton accesskey="R" alt="Click to Reset"
validateClient="false" immediate="true"
action="#{regionMaster.reset}" value="Reset" />
</prime:column>
<prime:column colspan="1">
<prime:commandButton accesskey="D"
onclick="if (!confirm('Are you sure you want to delete?')) return false"
alt="Click to Delete" actionListener="#{regionMaster.delete}"
validateClient="false" immediate="true" value="delete">
</prime:commandButton>
</prime:column>
</prime:row>
</prime:panelGrid>
</prime:panel></td>
</tr>
</table>
</div>
</h:form>
</ui:composition>
</html>
MyBean is
package com.sst.cms.web.beans;
import javax.faces.bean.RequestScoped;
import org.primefaces.context.RequestContext;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.inject.Named;
#ManagedBean(name="regionMaster",eager=false)
#SessionScoped
#Named("regionMaster")
public class RegionMasterBean implements Serializable {
//private static final FacesMessage RegionList = null;
public RegionMasterBean() {
}
private String regionId;
private String regionName;
private String createdBy;
private Date createdDate;
private String modifiedBy;
private Date modifiedDate;
private String entity;
private ArrayList<RegionMasterBean> regionList;
public String getRegionId() {
System.out.println("Region id======"+regionId);
return regionId;
}
public void setRegionId(String regionId) {
System.out.println("Region id======"+regionId);
this.regionId = regionId;
}
// other getter+setter
public String save(){
System.out.println("Bean is calleddddddddd");
return "SUCCESSFUL";
}
public void reset(){
this.regionId = "";
this.regionName = "";
}
public String delete(){
return "Sucess";
}
// public String setId(){
// System.out.println("Region iddddddddddddd");
//
// FacesContext fc = FacesContext.getCurrentInstance();
// this.regionId = getCountryParam(fc);
//
// return regionId;
// }
//
public ArrayList<RegionMasterBean> regionListLoad(){
regionList = new ArrayList<RegionMasterBean>();
RegionMasterBean dto = new RegionMasterBean();
dto.setRegionId("REG001");
dto.setRegionName("India");
RegionMasterBean dto1 = new RegionMasterBean();
dto1.setRegionId("REG002");
dto1.setRegionName("Afganisthan");
regionList.add(dto);
regionList.add(dto1);
return regionList;
}
public ArrayList<RegionMasterBean> getRegionList() {
return regionList;
}
public void setRegionList(ArrayList<RegionMasterBean> regionList) {
this.regionList = regionList;
}
public String saveSetting(){
System.out.println("this is calleddddddd");
this.regionId = "Roo1";
return regionId;
}
#PostConstruct
public void regionList() {
System.out.println("region list is calledddddddd");
RequestContext.getCurrentInstance().openDialog("RegionList");
System.out.println("region list is calledddddddd");
}
}
It works fine with the project where i have jsf 1.2 but when i add this to a new project with jsf 2.2 it shows the error
I want to develop a JSF Page which lets user edit a Employee from database. I loaded list of all employees in h:selectOneMenu. and second thing i want that with valueChangeEvent employee detail should be loaded in corresponding h:inputText. but nothing happens with every valueChangeEvent. So, where is the problem in codes.
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core">
<h:head>
<title>Facelet Title</title>
</h:head>
<h:body>
<div id="hdr">
<h1>Vinweb Services</h1>
<hr/>
</div>
;
<div id="mnu" style="height: 50px; width: auto; background: skyblue;">
<h:form>
<h:commandLink value="Home" action="index"/>
<h:outputText value=" "/>
<h:commandLink value="Create" action="create"/>
<h:outputText value=" "/>
<h:commandLink value="View" action="view"/>
<h:outputText value=" "/>
<h:commandLink value="Edit" action="edit"/>
</h:form>
</div>
<div id="cnt">
<h:form>
<h:panelGrid columns="2">
<h:outputLabel value="Select an Employee"/>
<h:selectOneMenu value="#{esb.empName}" onchange="submit()" valueChangeListener="#{esb.loadEmployeeDetail}">
<f:selectItems value="#{esb.employeeList}"/>
</h:selectOneMenu>
<h:outputLabel value="Employee Code"/>
<h:inputText value="#{esb.empCode}" required="true"/>
<h:outputLabel value="Employee Name"/>
<h:inputText value="#{esb.empName}" required="true"/>
<h:outputLabel value="Joining Date"/>
<h:inputText value="#{esb.joinDate}" required="true">
<f:convertDateTime pattern="MM/yy"/>
</h:inputText>
<h:outputLabel value="Salary"/>
<h:inputText value="#{esb.salary}" required="true"/>
<h:commandButton value="Update" action="#{esb.updateEmployeeDetail}"/>
</h:panelGrid>
</h:form>
</div>
</h:body>
</html>
Backing Bean:
package ems.bean;
import javax.inject.Named;
import javax.enterprise.context.SessionScoped;
import java.io.Serializable;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Date;
import javax.annotation.Resource;
import javax.faces.event.ValueChangeEvent;
import javax.sql.DataSource;
#Named(value = "esb")
#SessionScoped
public class EmployeeServiceBean implements Serializable {
#Resource(name = "JPA4A")
private DataSource ds;
// Member Declaration
private String empCode;
private String empName;
private Date joinDate;
private long salary;
private ArrayList empList;
// Service Code Segment
// This method will publish all emloyees in table to selectOneMenu
public ArrayList getEmployeeList() throws SQLException{
empList = new ArrayList();
Connection con = ds.getConnection();
try{
Statement stmt = con.createStatement();
ResultSet rslt = stmt.executeQuery("SELECT empName FROM Employee");
while(rslt.next()){
empList.add(rslt.getString("empName"));
}
}
catch(SQLException se) {
throw new SQLException();
}
finally{
con.close();
}
return empList;
}
// This method should load selected empoyee's details in inputText fields
public void loadEmployeeDetail(ValueChangeEvent evt) throws SQLException{
String emp = evt.getNewValue().toString();
Connection con = ds.getConnection();
try{
Statement stmt = con.createStatement();
String qry = "SELECT * FROM Employee WHERE empName = '"+emp+"'";
ResultSet rslt = stmt.executeQuery(qry);
rslt.next();
this.empCode = rslt.getString("empCode");
this.empName = rslt.getString("empName");
this.joinDate = rslt.getDate("joinDate");
this.salary = rslt.getLong("salary");
}
catch(SQLException se) {
se.printStackTrace();
}
finally{
con.close();
}
}
public void updateEmployeeDetail() throws SQLException{
Connection con = ds.getConnection();
try{
Statement stmt = con.createStatement();
boolean rs = stmt.execute("UPDATE Employee SET empCode='"+empCode+"', empName='"+empName+"', joinDate='"+joinDate+"', salary="+salary);
}
catch(SQLException se) {
throw new SQLException();
}
finally{
con.close();
}
}
// Property Getter & Setter code segment
public String getEmpCode() {
return empCode;
}
public void setEmpCode(String empCode) {
this.empCode = empCode;
}
public String getEmpName() {
return empName;
}
public void setEmpName(String empName) {
this.empName = empName;
}
public Date getJoinDate() {
return joinDate;
}
public void setJoinDate(Date joinDate) {
this.joinDate = joinDate;
}
public long getSalary() {
return salary;
}
public void setSalary(long salary) {
this.salary = salary;
}
}
The valueChangeListener is the wrong tool for the job.
You're here doing a onchange="submit()" which submits the entire form, including those required fields which in turn caused validation errors which in turn failed to reach your attention because you don't have any <h:message(s)> for them. If you have placed a <h:messages/> inside the form, or have paid more love and attention to server logs, you should have been notified of those required="true" validation errors.
You need <f:ajax listener>.
Replace
<h:selectOneMenu value="#{esb.empName}" onchange="submit()" valueChangeListener="#{esb.loadEmployeeDetail}">
<f:selectItems value="#{esb.employeeList}"/>
</h:selectOneMenu>
by
<h:selectOneMenu value="#{esb.empName}">
<f:selectItems value="#{esb.employeeList}"/>
<f:ajax listener="#{esb.loadEmployeeDetail}" render="#form" />
</h:selectOneMenu>
and replace
public void loadEmployeeDetail(ValueChangeEvent evt) throws SQLException{
String emp = evt.getNewValue().toString();
// ...
}
by
public void loadEmployeeDetail() throws SQLException{
String emp = empName; // You can also just use `empName` directly.
// ...
}
See also:
When to use valueChangeListener or f:ajax listener?
I read many similar questions, but I cannot figure out how to solve my problem:
I wrote a composite component backed by a view-scoped, self-contained managed bean.
The component consists of an autocomplete textbox with a button that opens a dialog. The user can select an item either by name (autocomplete) or selecting a node in a tree (dialog).
The backing bean implements all the stuff needed (data access, tree-logics etc) and should expose the selected item (as a POJO).
Now I have 2 problems:
Due to the complexity of the tree management, selectedObj property is accessed by a getter and a setter that do some stuff in the bean: they are not simply accessing a class field. Now I'm passing the entire bean as an attribute. How can I just make the bean's selectedObj the "value" attribute of my composite component?
How can I use multiple instance of my component in the same view?
Here is an example of the component:
<cc:interface>
<cc:attribute name="bean" type="com.yankee.OUTreeBean" required="true"/>
<cc:attribute name="listener" method-signature="void listener()"/>
</cc:interface>
<cc:implementation>
<p:dialog id="#{cc.id}_dialog" widgetVar="_dlg" header="Select OU" modal="true" dynamic="true" >
<p:toolbar>
<!-- some buttons to refresh, expand, collapse etc. -->
</p:toolbar>
<p:tree id="#{cc.id}_tree" value="#{cc.attrs.bean.root}" var="node"
selectionMode="single"
selection="#{cc.attrs.bean.selectedNode}">
<p:ajax event="select" update="#form" listener="#{cc.attrs.listener}" oncomplete="if (!args.validationFailed) _dlg.hide()" />
<p:treeNode>
<h:outputText value="#{node.OU_NAME}" />
</p:treeNode>
</p:tree>
</p:dialog>
<p:autoComplete id="#{cc.id}_inner" value="#{cc.attrs.bean.selectedObj}" completeMethod="#{cc.attrs.bean.completeObj}"
var="obj" itemLabel="#{obj.OU_NAME}" itemValue="#{obj}"
forceSelection="true"
converter="ouConverter"
multiple="false"
minQueryLength="2">
<p:ajax event="itemSelect" listener="#{cc.attrs.listener}" update="#form"/>
</p:autoComplete>
<div style="float: right">
<p:commandButton id="bSearch" icon="ui-icon-search" onclick="_dlg.show()"/>
</div>
</cc:implementation>
The backing bean of the COMPONENT:
#ManagedBean
#ViewScoped
public class OUTreeBean implements Serializable {
private static final long serialVersionUID = 1L;
private List<OU> data; // Data as plain list
protected TreeNode root; // root node of data as a tree
protected TreeNode selectedNode;
#PostConstruct
private void init() throws SQLException {
refreshData();
}
public OU getSelectedObj() {
if (selectedNode == null) {
return null;
}
return ((OU) selectedNode.getData());
}
public void setSelectedObj(OU ou) {
// Find the right tree node and do whatever needed
}
public TreeNode selectedNode getSelectedNode() {
// Blah blah
}
public void setSelectedNode(TreeNode selectedNode) {
// Blah blah
}
public List<OU> completeObj(String namePattern) {
// Autocomplete handler
}
public void refreshData() {
// Blah blah
}
// etc...
}
The using page excerpt:
<ism:selectOUTree id="cbSelectOu" bean="#{myBean.ouFilterBean}" listener="#{myBean.onOUChange}"/>
The backing bean of the PAGE:
#ManagedBean
#ViewScoped
public class MyBean implements Serializable {
private static final long serialVersionUID = 1L;
#ManagedProperty("#{oUTreeBean}")
private OUTreeBean ouFilterBean;
public void onOUChange() throws SQLException {
// Blah blah
}
}
I had the same problem few days ago. Just like you I used ManagedBean as an object that should do the job. After some time I figured out that I should just create FacesComponent. I'm new in JSF so it wasn't that easy to find the solution but it solved all my problems. This is how does it work:
view.xhtml
<h:body>
<cc:interface componentType="playerComponent">
<cc:attribute name="playerId" required="true"/>
</cc:interface>
<cc:implementation>
<c:set var="inplaceId" value="inplace-#{cc.attrs.playerId}" />
<c:set var="outputId" value="output-#{cc.attrs.playerId}" />
<h:form id="form-#{cc.attrs.playerId}">
<p:inplace editor="false" widgetVar="#{inplaceId}">
<h:inputText value="#{cc.player.name}" id="outputId"/>
<p:commandButton onclick="#{inplaceId}.save()" action="#{cc.save}" update="#{outputId}" value="save" />
<p:commandButton onclick="#{inplaceId}.cancel()" update="#{outputId}" value="cancel" />
</p:inplace>
</h:form>
</cc:implementation>
</h:body>
PlayerComponent.java
#FacesComponent("playerComponent")
public class PlayerComponent extends UINamingContainer {
private Player player;
private void init() {
Object idObj = getAttributes().get("playerId");
if (idObj != null) {
// create player object
}
}
public void save() {
// save player object
}
public Player getPlayer() {
if (player == null) {
init();
}
return player
}
}
Player.java (entity)
public class Player {
private name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
As I wrote I'm new in JSF and probably player object should be created in different way (using #PostConstruct on in constructor?) but this work.
I have a jsf template page. In this template i would like to use component with parameter. Actually i would like to iterate over collection. This collection should be determined by parameters from particular page. Parameter name is selectedMenu. How can i use this in my bean?
<div id="notes">
selectedMenu: #{selectedMenu}
<h:form>
<h:inputHidden value="#{notatkaController.searchForm.kategoria}">
<f:param value="#{selectedMenu}" />
</h:inputHidden>
<ui:repeat value="#{notatkaController.items}" var="item" varStatus="iter">
<f:param value="#{selectedMenu}" />
<p class="q-title"><strong><h:outputText value="#{item.ntaData}" /></strong></p>
<p class="answer"><h:outputText value="#{item.ntaDane}" escape="false" /></p>
</ui:repeat>
<span>Moje notatki</span>
<textarea>Tu wpisz treść swojej notatki</textarea>
<span>[+] dodaj notatkę</span>
</h:form>
</div>
My bean:
#ManagedBean(name = "notatkaController")
#ViewScoped
public class NotatkaController extends AbstractController<Notatka> implements Serializable {
#EJB
private pl.alfaprojekt.model.session.NotatkaFacade ejbFacade;
private NotatkaSearchForm searchForm;
public DataModel getItems() {
if (items == null)
items = getPagination().createPageDataModel();
return items;
}
public PaginationHelper getPagination() {
if (pagination == null) {
if (paginationSize == null)
paginationSize = 10;
pagination = new PaginationHelper(paginationSize) {
#Override
public int getItemsCount() {
return getFacade().countByParam(getSearchForm());
}
#Override
public DataModel createPageDataModel() {
if (rapId == null)
return new ListDataModel(getFacade().findRangeByParam(getSearchForm(), new int[]{getPageFirstItem(), getPageFirstItem() + getPageSize()}));
else {
Long uzyId = SessionUtil.getUser().getUzyId();
return new ListDataModel(convertToRaportWierszList(getFacade().findRangeByParam(getSearchForm(), new int[]{getPageFirstItem(), getPageFirstItem() + getPageSize()}), uzyId));
}
}
};
}
return pagination;
}
}
I am not sure I understood the question but the question I answer is this:
I want to dynamically display something. I want to tell it what to display when the page gets accessed.
View:
You could then use the following:
<f:event listener="#{myBean.myMethod}" type="preRenderView" />
Bean:
public void myMethod(ComponentSystemEvent event){
//your logic here
}
With parameter:
<f:metadata>
<f:event listener="#{myBean.myMethod}" type="preRenderView" id="fevent"/>
<f:attribute name="myParam" value="#{mySecondBean.param)" />
</f:metadata>
And
public void myMethod(ComponentSystemEvent event){
String id = (String) event.getComponent().getAttributes().get("myParam");
}
I am having trouble in using a JSF composite-component in the right way. I put some components together and everything was working. Then I just extracted the code to a composite-component, and passed the corresponding attributes and suddenly I am getting conversation exceptions.
<composite:interface>
<composite:attribute name="selectedIDs" type="java.util.Collection" required="true"/>
<composite:attribute name="selectItems" type="java.util.List" required="true" />
<composite:attribute name="addAction" required="true"/>
<composite:attribute name="deleteAction" required="true"/>
<composite:attribute name="deleteButtonDisabled" />
<composite:attribute name="ajaxListener" method-signature="void listener(javax.faces.event.AjaxBehaviorEvent)"/>
</composite:interface>
<composite:implementation>
<div class="myClass">
<h:outputStylesheet library="views" name="selectManyControlPanel.css" target="head" />
<h:form>
<h:selectManyListbox value="#{cc.attrs.selectedIDs}">
<f:selectItems value="#{cc.attrs.selectItems}" />
<f:ajax render="delete"
listener="#{cc.attrs.ajaxListener}" />
</h:selectManyListbox>
<br />
<h:commandButton id="delete" value="Delete"
disabled="#{cc.attrs.deleteButtonDisabled}"
action="#{cc.attrs.deleteAction}" />
<h:commandButton id="add" value="Add" action="#{cc.attrs.addAction}"/>
</h:form>
</div>
</composite:implementation>
Here is the page where I am using the newly created component
<view:selectManyControlPanel
selectedIDs="#{bean.selectedIds}"
selectItems="#{bean.listOfSelectItems}"
addAction="#{bean.addNew}"
deleteAction="#{bean.deleteSelection}"
ajaxListener="#{bean.selectionChanged}"
deleteButtonDisabled="#{bean.deleteButtonDisabled}" />
Bean (some methods skipped an parts renamed)
package views;
#SuppressWarnings("serial")
#Named
#RequestScoped
public class Bean implements Serializable, IOverviewView {
#Inject
Presenter presenter;
private boolean deleteButtonDisabled;
private List<SelectItem> listOfSelectItems;
private Set<Long> selectedIds;
public Bean(){
deleteButtonDisabled = true;
listOfSelectItems = new ArrayList<SelectItem>(10);
}
public void selectionChanged(AjaxBehaviorEvent event){
if(selectedIds.isEmpty())
deleteButtonDisabled = true;
else
deleteButtonDisabled = false;
}
public void deleteBikes(){
presenter.delete(selectedIds);
}
public void addNew(){
presenter.addNew();
}
public List<SelectItem> getListOfSelectItems() {
return listOfSelectItems;
}
public Set<Long> getSelectedIds() {
return selectedIds;
}
#PostConstruct
public void init(){
System.out.println("INITIALIZING BEAN: " + this.getClass().getName());
this.presenter.setView(this);
this.presenter.init();
}
public boolean isDeleteButtonDisabled() {
return deleteButtonDisabled;
}
#Override
public void setDeleteButtonEnabled(boolean isEnabled) {
deleteButtonDisabled = !isEnabled;
}
public void setListOfSelectItems(List<SelectItem> list) {
this.listOfSelectItems = list;
}
public void setSelectedIds(Set<Long> selectedIds) {
this.selectedIds = selectedIds;
}
#Override
public void updateBikesList(Set<ViewObject> objectsToDisplay) {
updateList(objectsToDisplay);
}
private void updateList(Set<ViewObject> objectsToDisplay){
listOfSelectItems.clear();
for (ViewObject vO : objectsToDisplay) {
final String label = vO.getManufacturer() + ", " + vO.getModel() + " (" + vO.getYear() + ")";
listOfSelectItems.add(new SelectItem(vO.getId(), label));
}
}
....
}
Exception
javax.el.ELException: /resources/views/selectManyControlPanel.xhtml #25,56 value="#{cc.attrs.selectedIDs}": /index.xhtml #21,70 selectedIDs="#{bean.selectedIds}": Cannot convert [Ljava.lang.String;#1e92093 of type class [Ljava.lang.String; to interface java.util.Set
The only thing that changed is that I am using the composition instead of the plain code. The EL-expressions are still the same. Can someone enlighten me please? I expected that the parameters are just passed through but obviously not...
This is related to Mojarra issue 2047. It's scheduled to be fixed in the upcoming 2.2.
The issue ticket also proposes the following workaround:
<view:selectManyControlPanel
selectedIDsBean="#{bean}"
selectedIDsProperty="selectedIds"
with in CC interface
<composite:attribute name="selectedIDsBean" required="true"/>
<composite:attribute name="selectedIDsProperty" required="true"/>
and in CC implementation
<h:selectManyListbox value="#{cc.attrs.selectedIDsBean[cc.attrs.selectedIDsProperty]}">