Datatable inside programatically added composite component
Asked Answered
P

1

1

Referring to my earlier question (Programmatically create and add composite component in backing bean) I have succesfully able to add composite components from backing bean. Now I have a new problem as composite component with lazy datatable in it does not call load() method at all. There was bug report about this (https://code.google.com/p/primefaces/issues/detail?id=3258) but that is marked to be related to PF3.0.RC1 and I have no clue if it is fixed for version 3.5 I am using.

I am using the exactly same code BalusC mentioned with possibility to add value expressions to the composite component:

public void includeCompositeComponent(UIComponent parent, String libraryName, String resourceName, String id, Map<String, String> valueExpressions) {
    ...
    if (!valueExpressions.isEmpty()) {
        ExpressionFactory factory = application.getExpressionFactory();
        ELContext ctx = context.getELContext();
        for (Map.Entry<String, String> entry : valueExpressions.entrySet()) {
            ValueExpression expr = factory.createValueExpression(ctx, entry.getValue(), String.class);
            composite.setValueExpression(entry.getKey(), expr);
        }
    } 
    ...
}

And this is my composite component testDatatable.xhtml:

<cc:interface>
    <composite:attribute name="model" required="true" type="org.primefaces.model.LazyDataModel"/>
    <composite:attribute name="id" default="dataTable"/>
</cc:interface>
<cc:implementation>
    <h:form id="dataTableForm">    
        <p:dataTable id="#{cc.attrs.id}" value="#{cc.attrs.model}" var="test" paginator="true" rows="10"
                     paginatorTemplate="{RowsPerPageDropdown} {FirstPageLink} {PreviousPageLink} {CurrentPageReport} {NextPageLink} {LastPageLink}"
                     rowsPerPageTemplate="5,10,15,20" lazy="true">
            <p:column>
                <h:outputText value="#{test.car.model}"/>
            </p:column>
         </p:dataTable>
    </h:form>
</cc:implementation>

And here is the creation of the composite component from backing bean:

Map<String, String> v = new HashMap<String, String>();
v.put("model", "#{testBean.lazyModel}");
addCompositeComponent(rootPanel, "comp", "testDatatable.xhtml", "table", v);

Here is the lazy data model I am loading in @PostConstruct

pulic class TestBean {
    private TestLazyDataModel<TestClass> lazyModel;

    @PostConstruct
    public void init() {
        lazyModel = new TestLazyDataModel();
    }

    public TestLazyDataModel<TestClass> getLazyModel() {
        return lazyModel;
    }

    class TestLazyDataModel extends LazyDataModel<TestClass> {
        @Override
        public List<TestClass> load(int first, int pageSize, String sort, SortOrder sortOrder, Map<String, String> filters) {
            List<TestClass> ret = new ArrayList<TestClass>();
            TestClass t = new TestClass();
            Car c = new Car("Volvo");
            t.setCar(c);
            ret.add(t);
            return ret;
        }
    }
}

And some helper classes:

public class TestClass {
    private Car car;

    public void setCar(Car car) {
        this.car = car;
    }

    public Car getCar() {
        return car;
    }
}

public class Car {
    public String model;

    public Car(String model) {
        this.model = model;
    }

    public String getModel() {
        return model;
    } 
}

In conclusion as the page is now opened:

  1. The bean creates the lazy data model ok
  2. The lazy data model is correctly fetched from the composite component
  3. When the datatable tries to loop through the items in it the error: The class 'java.lang.String' does not have the property 'car'

Changing the <h:outputText value="#{test.car.model}"/> to <h:outputText value="#{test.class.name}"/> also java.lang.String but does not crash this time. When debugging this the load() method of the TestLazyDataModel is never called.

Also to make this even weirder is that if I use the same composite component from any other xhtml page like:

<comp:testDatatable model="#{anotherBean.model}"> 

it works fine. What am I missing? Is this related somehow to the rendering order of the components? Any help is highly appreciated!

Phagocytosis answered 17/4, 2013 at 9:2 Comment(0)
P
3

Just got it to work.. Changing the composite component value expression include code to use Object.class instead String.class:

public void includeCompositeComponent(UIComponent parent, String libraryName, String resourceName, String id, Map<String, String> valueExpressions) {
    ...
    if (!valueExpressions.isEmpty()) {
        ExpressionFactory factory = application.getExpressionFactory();
        ELContext ctx = context.getELContext();
        for (Map.Entry<String, String> entry : valueExpressions.entrySet()) {
            ValueExpression expr = factory.createValueExpression(ctx, entry.getValue(), Object.class);
            composite.setValueExpression(entry.getKey(), expr);
        }
    } 
    ...
}

did the trick. Hope this helps someone else too!

Phagocytosis answered 17/4, 2013 at 10:46 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.