Assign 'value expression' in place of '

2019-07-01 10:45发布

问题:

In my composite component, I iterate a list<list<javaDetailClass>>. I get all my <h:commandButon> attribute's values through value expression like #{iterator.value}. But the problem comes with attribute action, where action accepts only method expression. whereas I can assign only value expression there, resulting in MethodNotFoundException

<cc:interface>
    <cc:attribute name="formElements" />
</cc:interface>
<cc:implementation>
    <c:forEach items="#{cc.attrs.formElements}" var="element">
        <c:forEach items="#{element}" var="iterator">

                <h:commandButton id="#{iterator.id}" 
                value="#{iterator.value}"

                action="#{iterator.action}">

                </h:commandButton>
        </c:forEach>
  </c:forEach>
</cc:implementation>

Can anyone help me in fixing this? Thanks in advance.

UPDATE

this will be the detail class in my situation,

package com.stackoverflow.test;

public class TestData {

/*Properties based on the implementation of your composite.
Change type where it is needed*/
private String id; 
private String value; 
private String attributeName; 
private String action; 

public TestData() {
}

/*Getters and setters omitted*/


}

Bean.java simply holds an ArrayList of ArrayList. The constructor simply created five TestData objects and assigns some default value to its attributes.

package com.stackoverflow.test;

import java.util.ArrayList;
import javax.faces.bean.*; 

@ManagedBean
@RequestScoped
public class Bean {

private ArrayList<ArrayList<TestData>> list = new ArrayList<ArrayList<TestData>>(); 

public Bean() {
    ArrayList<TestData> testDataList = new ArrayList<TestData>(); 
    TestData data; 

    for(int i = 0; i < 5; i++) { 
        data = new TestData(); 
        data.setId("ID" + i);
        data.setValue("VALUE" + i);
        data.setAttributeName("ATTRIBUTE" + i);
        /**this sets the action attribute of TestData with a API from some other managed bean**/
        data.setAction("someOtherManagedbean.someactionAPI");
        testDataList.add(data);
    }

    list.add(testDataList); 
}

public ArrayList<ArrayList<TestData>> getList() {
    return list;
}

public void setList(ArrayList<ArrayList<TestData>> list) {
    this.list = list;
}

}

index.html simply calls the composite by assinging the value of "#{bean.list} to the name attribute

回答1:

I'm assuming that your TestData.java has the following method public String getAction() (since I'm seeing a setAction(String)) and not public String action(). Therefore, the reason why you are getting a MethodNotFoundException is because you are supplying the wrong method name to the action attribute. In your case it should be iterator.getAction and not iterator.action. You only supply the abbreviated names when an attribute is expecting a value expression. The interface below has been modifed.

    <cc:interface>
        <cc:attribute name="formElements" />
    </cc:interface>

    <cc:implementation>
        <c:forEach items="#{cc.attrs.formElements}" var="element">
            <c:forEach items="#{element}" var="iterator">
                <h:commandButton id="#{iterator.id}" 
                                 value="#{iterator.value}"

                                 action="#{iterator.getAction}">
                </h:commandButton>
            </c:forEach>
        </c:forEach>
    </cc:implementation>