Tiny
Tiny

Reputation: 27899

Command components inside a p:carousel wrapped by a p:dataGrid using LazyDataModel<T> do not invoke action(Listener)s, when the bean is request scoped

Example :

<p:dataGrid var="dRow" value="#{testBean}" lazy="true" rows="1" columns="1">
    <p:carousel var="cRow" value="#{dRow.subCategories}" headerText="#{dRow.catName}" itemStyle="width : 300px">
        <!--Show images but that part is excluded for brevity.-->
        <p:commandLink process="@this" value="#{cRow.subCatName}" actionListener="#{testBean.action(cRow)}"/>
    </p:carousel>
</p:dataGrid>

The managed bean :

@Named
@RequestScoped
public class TestBean extends LazyDataModel<Category> {

    @Inject
    private DataStore dataStore;
    private List<Category> categories;

    public TestBean() {}

    @PostConstruct
    private void init() {
        categories = dataStore.getCategories();
    }

    @Override
    public List<Category> load(int first, int pageSize, String sortField, SortOrder sortOrder, Map<String, Object> filters) {
        List<Category> list = dataStore.getCategories();
        setRowCount(list.size());
        return list;
    }

    public List<Category> getCategories() {
        return categories;
    }

    public void action(SubCategory subCategory) {
        System.out.println("action() invoked : " + subCategory.getSubCatName());
    }
}

The bean is decorated with @RequestScoped. DataStore is an application scoped bean where the List<Category> is created and stored.

The given command link does not trigger the action listener method (action()) in the managed bean unless either the bean is decorated with @ViewScoped (or wider) or the lazy data model is removed.

Thus, changing,

<p:dataGrid var="dRow" value="#{testBean}" .../>

to

<p:dataGrid var="dRow" value="#{testBean.categories}" .../>

will work i.e. the <p:commandLink> will invoke the action listener given (The lazy data model is excluded here. The given <p:dataGrid> is directly populated by a List<Category> from the backing bean).

Another alternative is to use a wider scoped bean like a view scoped bean as stated earlier.

Is it possible to use a request scoped bean along with a lazy data model in the given situation so that command components inside those components can work? I have many such view scoped beans just because of <p:commandLink>s inside a <p:carousel> wrapped by a <p:dataGrid> which could otherwise have simply been declared request scoped.


In case the application scoped bean where the list is maintained and the domain model classes are needed.

The application scoped bean :

@Named
@ApplicationScoped
public class DataStore {

    private List<Category> categories;

    public DataStore() {}

    @PostConstruct
    private void init() {
        categories = new ArrayList<>();

        Category category = new Category();
        category.setCatId(1L);
        category.setCatName("Animals");
        categories.add(category);

        List<SubCategory> subCategories = category.getSubCategories();

        SubCategory subCategory = new SubCategory();
        subCategory.setSubCatId(1L);
        subCategory.setSubCatName("Aquatic");
        subCategory.setCategory(category);
        subCategories.add(subCategory);

        subCategory = new SubCategory();
        subCategory.setSubCatId(2L);
        subCategory.setSubCatName("Aerial");
        subCategory.setCategory(category);
        subCategories.add(subCategory);

        subCategory = new SubCategory();
        subCategory.setSubCatId(3L);
        subCategory.setSubCatName("Mammals");
        subCategory.setCategory(category);
        subCategories.add(subCategory);
    }

    public List<Category> getCategories() {
        return categories;
    }
}

The domain class Category :

public class Category implements Serializable {

    private Long catId;
    private String catName;
    private List<SubCategory> subCategories = new ArrayList<>();
    private static final long serialVersionUID = 1L;

    public Category() {}

    public Long getCatId() {
        return catId;
    }

    public void setCatId(Long catId) {
        this.catId = catId;
    }

    public String getCatName() {
        return catName;
    }

    public void setCatName(String catName) {
        this.catName = catName;
    }

    public List<SubCategory> getSubCategories() {
        return subCategories;
    }

    public void setSubCategories(List<SubCategory> subCategories) {
        this.subCategories = subCategories;
    }

    @Override
    public int hashCode() {
        int hash = 7;
        hash = 47 * hash + Objects.hashCode(getCatId());
        return hash;
    }

    @Override
    public boolean equals(Object that) {
        if (!(that instanceof Category)) {
            return false;
        }

        return this == that || Objects.equals(getCatId(), ((Category) that).getCatId());
    }

    @Override
    public String toString() {
        return String.format("%s[catId=%d]", getClass().getCanonicalName(), getCatId());
    }
}

The domain class SubCategory :

public class SubCategory implements Serializable {

    private Long subCatId;
    private String subCatName;
    private Category category;
    private static final long serialVersionUID = 1L;

    public SubCategory() {}

    public Long getSubCatId() {
        return subCatId;
    }

    public void setSubCatId(Long subCatId) {
        this.subCatId = subCatId;
    }

    public String getSubCatName() {
        return subCatName;
    }

    public void setSubCatName(String subCatName) {
        this.subCatName = subCatName;
    }

    public Category getCategory() {
        return category;
    }

    public void setCategory(Category category) {
        this.category = category;
    }

    @Override
    public int hashCode() {
        int hash = 7;
        hash = 47 * hash + Objects.hashCode(getSubCatId());
        return hash;
    }

    @Override
    public boolean equals(Object that) {
        if (!(that instanceof SubCategory)) {
            return false;
        }

        return this == that || Objects.equals(getSubCatId(), ((SubCategory) that).getSubCatId());
    }

    @Override
    public String toString() {
        return String.format("%s[subCatId=%d]", getClass().getCanonicalName(), getSubCatId());
    }
}

Upvotes: 0

Views: 134

Answers (0)

Related Questions