Jsf f:setPropertyActionListener未在p:dataTable中调用

Jsf f:setPropertyActionListener未在p:dataTable中调用,jsf,jsf-2,primefaces,datatable,Jsf,Jsf 2,Primefaces,Datatable,我跟随PrimeFacesDataGrid showcase完成了我的datatable。我想为datatable的每一行显示一个edit imagebutton,单击后我想显示一个编辑对话框表单 问题是在commandlink单击时未触发setSelectedChannel方法,因此当对话框尝试访问selecteChannel字段时出现此错误: javax.el.PropertyNotFoundException: /WEB-INF/includes/channels.xhtml @54,91

我跟随PrimeFacesDataGrid showcase完成了我的datatable。我想为datatable的每一行显示一个edit imagebutton,单击后我想显示一个编辑对话框表单

问题是在commandlink单击时未触发setSelectedChannel方法,因此当对话框尝试访问selecteChannel字段时出现此错误:

javax.el.PropertyNotFoundException: /WEB-INF/includes/channels.xhtml @54,91 value="#{channelBean.selectedChannel.name}": Target Unreachable, 'selectedChannel' returned null
这是我的xhtml包含页面:

<ui:composition 
xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui">
<h:form id="channelForm">    
    <p:dataTable var="channel" value="#{channelBean.channels}">
        <p:column headerText="Name">
            <h:outputText value="#{channel.name}" />
        </p:column>

        <p:column headerText="Field 1">
            <h:outputText value="#{channel.field1}" />
        </p:column>

        <p:column headerText="Field 2">
            <h:outputText value="#{channel.field2}" />
        </p:column>

        <p:column headerText="ApiWriteKey">
            <h:outputText value="#{channel.apiWriteKey}" />
        </p:column>

        <p:column headerText="Edit">
            <p:commandLink update=":channelForm:panelEditCh" oncomplete="PF('dlg2').show();" title="Edit">
                <h:outputText styleClass="ui-icon ui-icon-search" style="margin:0 auto;" />
                <f:setPropertyActionListener value="#{channel}" target="#{channelBean.selectedChannel}" />
            </p:commandLink>
        </p:column>
    </p:dataTable>
    <p:dialog  id="dialogNewChannel" header="New Channel" widgetVar="dlg1" modal="false"  >
        <h:panelGrid columns="2" style="margin-bottom:10px" cellpadding="5">
            <p:outputLabel for="channelName" value="Channel name:" />
            <p:inputText id="channelName" value="#{channelBean.name}" />

            <p:outputLabel for="channelDesc" value="Channel description:" />
            <p:inputText id="channelDesc" value="#{channelBean.description}" />

            <p:outputLabel for="channelField1" value="Channel field 1:" />
            <p:inputText id="channelField1" value="#{channelBean.field1}" />
            <p:outputLabel for="channelField2" value="Channel field 2:" />
            <p:inputText id="channelField2" value="#{channelBean.field2}"  />
        </h:panelGrid>
        <p:commandButton id="saveButton" value="Save" action="#{channelBean.saveChannel}" update="channelForm" ajax="true" />
        <p:commandButton value="Cancel" type="button" action="#{channelBean.resetForm}" onclick="PF('dlg1').hide();" />

    </p:dialog>   
    <p:dialog  id="dialogEditChannel" header="Edit Channel" widgetVar="dlg2" modal="false"  >
        <h:panelGrid id="panelEditCh" columns="2" style="margin-bottom:10px" cellpadding="5">
            <p:outputLabel for="channelNameEdit" value="Channel name:" />
            <p:inputText id="channelNameEdit" value="#{channelBean.selectedChannel.name}" />

            <p:outputLabel for="channelDescEdit" value="Channel description:" />
            <p:inputText id="channelDescEdit" value="#{channelBean.selectedChannel.description}" />

            <p:outputLabel for="channelField1Edit" value="Channel field 1:" />
            <p:inputText id="channelField1Edit" value="#{channelBean.selectedChannel.field1}" />
            <p:outputLabel for="channelField2Edit" value="Channel field 2:" />
            <p:inputText id="channelField2Edit" value="#{channelBean.selectedChannel.field2}"  />
        </h:panelGrid>
        <p:commandButton id="saveButtonEdit" value="Save" action="#{channelBean.saveChannel}" update="channelForm" ajax="true" />
        <p:commandButton value="Cancel" type="button" action="#{channelBean.resetForm}" onclick="PF('dlg2').hide();" />

    </p:dialog>  
    <p:spacer></p:spacer>
    <p:spacer></p:spacer>
    <p:commandButton value="New Channel" type="button" onclick="PF('dlg1').show();" />
     <!--  <p:blockUI block="dialogNewChannel" trigger="saveButton">  

            <p:graphicImage name="images/ajax-loader-large.gif"/>  
    </p:blockUI>
    -->
</h:form> 

和ManagedBean:

@ManagedBean
@ViewScoped
public class ChannelBean implements Serializable {
/**
 * 
 */
private static final long serialVersionUID = -1668407926998690759L;
private String idChannel;
private String apiWriteKey;
private String name;
private String description;
private String userId;
private String field1;
private String field2;

private Channel selectedChannel;


private List<Channel> channels= new ArrayList<Channel>() ;

@PostConstruct
public void populateChannelList(){
    refreshList();
}
public void refreshList(){
    HttpSession session = Util.getSession();
    int idUser=-1;
    if(session!=null &&session.getAttribute("idUser")!=null){
        idUser=(int) session.getAttribute("idUser");
    }
    channels=ChannelDAO.getChannels(idUser);

}


public void saveChannel(){
    ....
}
public void resetForm(){
    idChannel="";
    apiWriteKey="";
    name="";
    description="";
    userId="";
    field1="";
    field2="";
}

public String getIdChannel() {
    return idChannel;
}
public void setIdChannel(String idChannel) {
    this.idChannel = idChannel;
}
public String getApiWriteKey() {
    return apiWriteKey;
}
public void setApiWriteKey(String apiWriteKey) {
    this.apiWriteKey = apiWriteKey;
}
public String getName() {
    return name;
}
public void setName(String name) {
    this.name = name;
}
public String getDescription() {
    return description;
}
public void setDescription(String description) {
    this.description = description;
}
public String getUserId() {
    return userId;
}
public void setUserId(String userId) {
    this.userId = userId;
}
public String getField1() {
    return field1;
}
public void setField1(String field1) {
    this.field1 = field1;
}
public String getField2() {
    return field2;
}
public void setField2(String field2) {
    this.field2 = field2;
}

public List<Channel> getChannels() {
    return channels;
}
public void setChannels(List<Channel> channels) {
    this.channels = channels;
}

public Channel getSelectedChannel() {
    return selectedChannel;
}
public void setSelectedChannel(Channel selectedChannel) {
    this.selectedChannel = selectedChannel;
}

}
@ManagedBean
@视域
公共类ChannelBean实现了可序列化{
/**
* 
*/
私有静态最终长SerialVersionId=-16684079269989690759L;
专用字符串idChannel;
私有字符串apiWriteKey;
私有字符串名称;
私有字符串描述;
私有字符串用户标识;
私有字符串字段1;
私有字符串字段2;
专用频道选择频道;
私有列表通道=新的ArrayList();
@施工后
public void populateChannelList(){
刷新列表();
}
公共空刷新列表(){
HttpSession session=Util.getSession();
int idUser=-1;
if(session!=null&&session.getAttribute(“idUser”)!=null){
idUser=(int)session.getAttribute(“idUser”);
}
channels=ChannelDAO.getChannels(idUser);
}
公共void存储通道(){
....
}
公共表格(){
idChannel=“”;
apiWriteKey=“”;
name=“”;
description=“”;
userId=“”;
字段1=“”;
字段2=“”;
}
公共字符串getIdChannel(){
返回通道;
}
公共无效setIdChannel(字符串idChannel){
this.idChannel=idChannel;
}
公共字符串getApiWriteKey(){
返回apiWriteKey;
}
公共void setApiWriteKey(字符串apiWriteKey){
this.apiWriteKey=apiWriteKey;
}
公共字符串getName(){
返回名称;
}
公共void集合名(字符串名){
this.name=名称;
}
公共字符串getDescription(){
返回说明;
}
公共void集合描述(字符串描述){
this.description=描述;
}
公共字符串getUserId(){
返回用户标识;
}
public void setUserId(字符串userId){
this.userId=userId;
}
公共字符串getField1(){
返回字段1;
}
公共无效集合字段1(字符串字段1){
此字段1=字段1;
}
公共字符串getField2(){
返回字段2;
}
公共无效集合字段2(字符串字段2){
this.field2=field2;
}
公共列表getChannels(){
返回通道;
}
公共频道(列出频道){
这个。通道=通道;
}
公共频道getSelectedChannel(){
返回所选频道;
}
公共无效设置选定频道(频道选定频道){
this.selectedChannel=selectedChannel;
}
}

您在哪里初始化了
selectedChannel
专用频道selectedChannel;
)?此外,从底层Servlet API公开一个
HttpSession
实例是完全没有必要的。我认为这应该可以做到,我的做法与primefaces showcase中的做法完全相同:我尝试使用第一个频道列表初始化selectChannel,现在它可以工作了!非常感谢。但我不知道primefaces showcase如何工作。。。。我还有一个问题要问你,如何在不使用会话的情况下检索userId?你可以使用
ExternalContext
检索会话映射,例如
map sessionMap=FacesContext.getCurrentInstance().getExternalContext().getSessionMap()并将
userId
放入该映射中,但您最好选择自己的会话范围bean,在该bean中使用getter(以及setter,如果需要)声明
map
。公开底层Servlet API是一种代码味道。