Hi
I have a category entity which has
parent: category
name: string
and I create a tree of categories
I than have product with associated field: category
How can I filter (in a browse screen) products which belong to one category AND ALL its child categories?
Thank you
tsarev
(Daniil Tsaryov)
October 20, 2017, 12:56pm
#2
Hi,
Let’s begin with a screen XML descriptor. We need two data sources:
first data source to load Products
second data source to load Categories
<dsContext>
<groupDatasource id="productsDs"
class="com.company.filterentitiesconditionhierarchy.entity.Product"
view="product-view">
<query>
<![CDATA[select e from filterentitiesconditionhierarchy$Product e]]>
</query>
</groupDatasource>
<hierarchicalDatasource id="categoriesDs"
class="com.company.filterentitiesconditionhierarchy.entity.Category"
hierarchyProperty="parentCategory"
view="category-view">
<query>
<![CDATA[select e from filterentitiesconditionhierarchy$Category e]]>
</query>
</hierarchicalDatasource>
</dsContext>
The screen contains only LookupField and Table:
<lookupField id="categoriesField"
caption="Choose category:"
optionsDatasource="categoriesDs"/>
<groupTable id="productsTable"
width="100%">
<actions>
...
</actions>
<columns>
<column id="name"/>
<column id="price"/>
<column id="category"/>
</columns>
<rows datasource="productsDs"/>
<rowsCount/>
<buttonsPanel id="buttonsPanel"
alwaysVisible="true">
...
</buttonsPanel>
</groupTable>
Then we subscribe to LookupField value change:
@Inject
private HierarchicalDatasource<Category, UUID> categoriesDs;
@Inject
private GroupDatasource<Product, UUID> productsDs;
@Inject
private LookupField categoriesField;
@Override
public void ready() {
// save all products
final List<Product> allProducts = new ArrayList<>(productsDs.getItems());
categoriesField.addValueChangeListener(e -> {
Category category = (Category) e.getValue();
if (category == null) {
// show all prducts if category is not set
putProductsToDs(allProducts);
} else {
// filter suitable products by the selected category
List<Product> suitableProducts = collectSuitableProducts(category, allProducts);
// update data source
putProductsToDs(suitableProducts);
}
});
}
Filtering and collecting Products:
private List<Product> collectSuitableProducts(Category category, List<Product> allProducts) {
List<Category> categories = collectCategoriesRecursively(category);
return allProducts.stream()
.filter(p -> categories.contains(p.getCategory()))
.collect(Collectors.toList());
}
Walking through Categories tree and collecting items:
private List<Category> collectCategoriesRecursively(Category parentCategory) {
List<Category> categories = new ArrayList<>();
categories.add(parentCategory);
for (UUID uuid : categoriesDs.getChildren(parentCategory.getId())) {
Category category = categoriesDs.getItem(uuid);
//noinspection ConstantConditions
if (categoriesDs.getChildren(category.getId()).isEmpty()) {
categories.add(category);
continue;
}
categories.addAll(collectCategoriesRecursively(category));
}
return categories;
}
Updating data source:
private void putProductsToDs(List<Product> products) {
productsDs.clear();
products.forEach(productsDs::addItem);
((DatasourceImpl) productsDs).setModified(false);
}
Best regards,
Daniil.