h:commandLink not working inside dataTable

2019-09-11 13:53发布

问题:

In my JSF file I have below at the start.

<h:form><h:commandLink value="Create New Staff Account" action="adminCreateStaffMember"/></h:form>.

By use of this, when I create on Create New Staff Account I get re-directed to the page where I have form to create new account.

BUT, When I use the same inside dataTable, NO ACTION is taken. I am still on same page :(

<h:dataTable var="c" value="#{newStaffMemberServiceBean.newStaffMemberDataBeanList}"
  styleClass="order-table"
  headerClass="order-table-header"
  rowClasses="order-table-odd-row,order-table-even-row"
  border="1" id="staffListDataTable" width="100%">

  <h:column>
    <f:facet name="header">
       Staff Member Name
    </f:facet>
    <h:form><h:commandLink value="Create New Staff Account" action="adminCreateStaffMember"/></h:form>
  </h:column>
</h:dataTable>

Actually what I wanted to print is details of respective staff member where I would be using f:setPropertyActionListener. But as above is not working, I won't go ahead.

Please suggest me where I am going wrong.

Update 1

My newStaffMemberServiceBean is in RequestScoped

@ManagedBean(name = "newStaffMemberServiceBean")
@RequestScoped
public class NewStaffMemberServiceBean {
    // some code
}

Update 2

HTML Generated are as below

Outside of dataTable

<div align="right">
<form id="j_idt35" name="j_idt35" method="post" action="/adminManageStaffMember" enctype="application/x-www-form-urlencoded">
<input type="hidden" name="j_idt35" value="j_idt35" />
<a href="#" onclick="mojarra.jsfcljs(document.getElementById('j_idt35'),{'j_idt35:j_idt36':'j_idt35:j_idt36'},'');return false">Create New Staff Account</a><input type="hidden" name="javax.faces.ViewState" id="javax.faces.ViewState" value="2664682277023387375:-3250423983171933030" autocomplete="off" />
</form>

Inside dataTable

<form id="staffListDataTable:0:j_idt43" name="staffListDataTable:0:j_idt43" method="post" action="/adminManageStaffMember" enctype="application/x-www-form-urlencoded">
<input type="hidden" name="staffListDataTable:0:j_idt43" value="staffListDataTable:0:j_idt43" />
<a href="#" onclick="mojarra.jsfcljs(document.getElementById('staffListDataTable:0:j_idt43'),{'staffListDataTable:0:j_idt43:j_idt45':'staffListDataTable:0:j_idt43:j_idt45'},'');return false">Create New Staff Account</a><input type="hidden" name="javax.faces.ViewState" id="javax.faces.ViewState" value="2664682277023387375:-3250423983171933030" autocomplete="off" />
</form>

回答1:

I would suggest a few modifications for your original code. First, don't use h:form for each of your commandLink, instead use one form for your dataTable. Second, the action will get executed only when it finds the component that triggered the aciton. If you use a request scoped list for your datatable then that list wont be there when the view is restored or may not match the original one which was used to create the view. You may have to change the managed bean from request scope to view scope or higher.

Third, as a suggestion, you can use h:outputLink or h:link instead of the commandLink and provide the f:param to simplify this, in which case you dont need the form also.



回答2:

Is your table being wrapped by another form ?

if that's the case and you got form inside form...

remove the form tags that wraps the <h:commandLink value="Create New Staff Account" action="adminCreateStaffMember"/>

something like this

<h:column>
    <f:facet name="header">
       Staff Member Name
    </f:facet>
    <h:commandLink value="Create New Staff Account" action="adminCreateStaffMember"/>
</h:column>


回答3:

I guess your commandLink action method is wrong setted. You have this code:

<h:commandLink value="Create New Staff Account" action="adminCreateStaffMember"/>

You should have something like this:

<h:commandLink value="Create New Staff Account"
    action="#{newStaffMemberServiceBean.adminCreateStaffMember"/>

Besides, like @Daniel has posted, you must have only 1 form to wrap your dataTable and the commandLinks inside the dataTable.

UPDATE:

There is an important things you must know:

If you have a list as an attribute of your managed bean, this list is used to display info (i.e. using a dataTable) and you want to include some button or link inside the datatable, your managed bean MUST have a reference of the list in the creator. This can be achieved by at least 2 ways:

  • Save and load the list from session (very bad design, and it pretty hard to maintain the code).
  • Set the bean to ViewScoped (JSF2.x perspective. If you're with JSF 1.2, you can try the a4j:keepAlive tag from RichFaces or t:saveState from MyFaces).

Having said this, and since you're using JSF 2, you can use the ViewScope on your bean. With this, the bean won't be recreated after doing a request on the same view, so the list will be saved automatically inside the bean. The bean should look like this:

@ManagedBean(name = "newStaffMemberServiceBean")
@ViewScoped
public class NewStaffMemberServiceBean implements Serializable {
    private List<StaffMember> lstStaffMember;
    //getters and setters...
    public NewStaffMemberServiceBean() {
        //populate the list...
        lstStaffMember = new ArrayList<StaffMember>();
    }

    //managing the navigation using the id as a parameter
    //additional, this can (and MUST BE) improved.
    public String viewStaffMemberDetails() {
        //get the id parameter from the link
        int id = Integer.valueOf(FacesContext.getCurrentInstance()
            .getExternalContext().getRequestParameterMap().get("id"));
        //searching that id in our staff member list
        for(StaffMember sm : lstStaffMember) {
            if (sm.getId() == id) {
                //setting the staff member object in session
                FacesContext.getCurrentInstance().getExternalContext()
                    .getSessionMap().put("staffMember", sm);
                //returning the name of the page we want to navigate
                return "adminCreateStaffMember";
            }
        }
        return "";
    }
}

Now, let's check the xhtml. It's pretty simple:

<h:form>
    Welcome
    <br />
    <h:dataTable
        value="#{newStaffMemberServiceBean.lstStaffMember}"
        var="staffMember">
        <h:column>
            <f:facet name="header">
                Name
            </f:facet>
            <h:outputText value="#{staffMember.name}" />
        </h:column>
        <h:column>
            <f:facet name="header">
                View Details
            </f:facet>
            <h:commandLink value="Show details"
                action="#{newStaffMemberServiceBean.viewStaffMemberDetails}">
                <f:param name="id" value="#{staffMember.id}" />
            </h:commandLink>
        </h:column>
    </h:dataTable>
</h:form>

And that's it! You can navigate to adminCreateStaffMember.xhtml with no problems, and use the staffmember object in the adminCreateStaffMember managed bean to show the data (details). I've tried this code myself (I'm in a new pc so I have to check the code before posting, install software, etc...).