Initialize a composite component based on the provided attributes

后端 未结 2 1264
滥情空心
滥情空心 2020-12-05 12:00

I\'m writing my custom table composite component with Mojarra JSF. I\'m also trying to bind that composite to a backing component. The aim is to be able to specify the numbe

相关标签:
2条回答
  • 2020-12-05 12:30

    As to the cause, UIComponent instances are inherently request scoped. The postback effectively creates a brand new instance with properties like values reinitialized to default. In your implementation, it is only filled during encodeXxx(), which is invoked long after decode() wherein the action event needs to be queued and thus too late.

    You'd better fill it during the initialization of the component. If you want a @PostConstruct-like hook for UIComponent instances, then the postAddToView event is a good candidate. This is invoked directly after the component instance is added to the component tree.

    <cc:implementation>
        <f:event type="postAddToView" listener="#{cc.init}" />
        ...
    </cc:implementation>
    

    with

    private List<String> values;
    
    public void init() {
        values = new ArrayList<String>();
        Integer num = (Integer) getAttributes().get("value");
    
        for (int i = 0; i < num; i++) {
            values.add("item" + i);
        }
    }
    

    (and remove the encodeBegin() method if it isn't doing anything useful anymore)

    An alternative would be lazy initialization in getValues() method.

    0 讨论(0)
  • 2020-12-05 12:33

    A simpler solution would be to store and retrieve values as part of the components state. Storing can happen during encodeBegin, and retrieving could directly happen within the getter:

    @FacesComponent("components.myTable")
    public class TestTable extends UINamingContainer {
        public void action() {
            System.out.println("Called");
        }
    
        @Override
        public void encodeBegin(FacesContext context) throws IOException {
            // Initialize the list according to the element number
            List<String> values = new ArrayList<>();
            Integer num = (Integer) getAttributes().get("itemNumber");
            for (int i = 0; i < num; i++) {
                values.add("item" + i);
            }
            getStateHelper().put("values",values);
            super.encodeBegin(context);
        }
    
        public List<String> getValues() {
            return (List<String>)getStateHelper().get("values");
        }
    }
    

    To avoid repeating the logic in getValues(), there could be additional parsing required in more complex cases, there should be a way to process and cache the attributes right after they become available, although I am not sure when and how at this point.

    Either way - this seemed to be the simplest way to solve this problem.

    0 讨论(0)
提交回复
热议问题