This sample demonstrates how to extend PrimeFaces with javascript. Tree component displays the available columns which are draggable. where as column headers have drop targets and dropping a treenode onto one of these adds the related property column to the datatable. Column headers can also be moved back to the tree.
<style>
.active-drop {
background-color: var(--primary-color);
}
.highlight-drop {
background-color: var(--primary-color);
}
</style>
<script>
function initDND() {
$('.ui-treenode-leaf').draggable({
helper: 'clone',
scope: 'treetotable',
zIndex: ++PrimeFaces.zindex
});
$('.ui-datatable .droppoint').droppable({
activeClass: 'active-drop',
hoverClass: 'highlight-drop',
tolerance: 'pointer',
scope: 'treetotable',
drop: function (event, ui) {
var property = ui.draggable.find('.ui-treenode-label').text(),
droppedColumnId = $(this).parents('th:first').attr('id'),
dropPos = $(this).hasClass('dropleft') ? 0 : 1;
treeToTable([
{name: 'property', value: property}
, {name: 'droppedColumnId', value: droppedColumnId}
, {name: 'dropPos', value: dropPos}
]);
}
});
$('.ui-datatable th').draggable({
scope: 'tabletotree',
helper: function () {
var th = $(this);
return th.clone().appendTo(document.body).css('width', th.width());
}
});
$('.ui-tree').droppable({
helper: 'clone',
scope: 'tabletotree',
activeClass: 'active-drop',
hoverClass: 'highlight-drop',
tolerance: 'touch',
drop: function (event, ui) {
tableToTree([
{name: 'colIndex', value: ui.draggable.index()}
]);
}
});
}
$(function () {
initDND();
});
</script>
<div class="card">
<h:form id="form">
<p:remoteCommand name="treeToTable" action="#{columnManagerView.treeToTable}" update="tree products"
oncomplete="initDND()"/>
<p:remoteCommand name="tableToTree" action="#{columnManagerView.tableToTree}" update="tree products"
oncomplete="initDND()"/>
<p:tree id="tree" value="#{columnManagerView.availableColumns}" var="column" style="margin-bottom:20px">
<p:treeNode>
<h:outputText value="#{column}"/>
</p:treeNode>
<p:treeNode type="column" icon="pi pi-ellipsis-v">
<h:outputText value="#{column.property}"/>
</p:treeNode>
</p:tree>
<p:dataTable id="products" var="product" value="#{columnManagerView.products}">
<p:columns value="#{columnManagerView.columns}" var="column">
<f:facet name="header">
<h:outputText style="float:left;display:block;height:20px;width:10px;border:0 none;"
styleClass="droppoint dropleft"/>
<h:outputText style="float:right;display:block;height:20px;width:10px;border:0 none;"
styleClass="droppoint dropright"/>
<h:outputText value="#{column.header}"/>
</f:facet>
<h:outputText value="#{product[column.property]}"/>
</p:columns>
</p:dataTable>
</h:form>
</div>
@Named
@ViewScoped
public class ColumnManagerView implements Serializable {
private static final List<String> VALID_COLUMN_KEYS = Arrays.asList("id", "code", "name", "description",
"price", "category", "quantity");
private List<ColumnModel> columns = new ArrayList<>();
private List<Product> products;
private TreeNode<Product> availableColumns;
@Inject
private ProductService service;
@PostConstruct
public void init() {
products = service.getProducts(9);
createAvailableColumns();
createDynamicColumns();
}
private void createAvailableColumns() {
availableColumns = new DefaultTreeNode("Root", null);
TreeNode root = new DefaultTreeNode("Columns", availableColumns);
root.setExpanded(true);
TreeNode id = new DefaultTreeNode("column", new ColumnModel("Id", "id"), root);
TreeNode code = new DefaultTreeNode("column", new ColumnModel("Code", "code"), root);
TreeNode name = new DefaultTreeNode("column", new ColumnModel("Name", "name"), root);
TreeNode description = new DefaultTreeNode("column", new ColumnModel("Description", "description"), root);
TreeNode price = new DefaultTreeNode("column", new ColumnModel("Price", "price"), root);
TreeNode category = new DefaultTreeNode("column", new ColumnModel("Category", "category"), root);
TreeNode quantity = new DefaultTreeNode("column", new ColumnModel("Quantity", "quantity"), root);
}
public void createDynamicColumns() {
String[] columnKeys = new String[]{"code", "name", "quantity"};
columns.clear();
for (String columnKey : columnKeys) {
String key = columnKey.trim();
if (VALID_COLUMN_KEYS.contains(key)) {
columns.add(new ColumnModel(columnKey.toUpperCase(), columnKey));
}
}
}
public void treeToTable() {
Map<String, String> params = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap();
String property = params.get("property");
String droppedColumnId = params.get("droppedColumnId");
String dropPos = params.get("dropPos");
String[] droppedColumnTokens = droppedColumnId.split(":");
int draggedColumnIndex = Integer.parseInt(droppedColumnTokens[droppedColumnTokens.length - 1]);
int dropColumnIndex = draggedColumnIndex + Integer.parseInt(dropPos);
//add to columns
this.columns.add(dropColumnIndex, new ColumnModel(property.toUpperCase(), property));
//remove from nodes
TreeNode<?> root = availableColumns.getChildren().get(0);
for (TreeNode node : root.getChildren()) {
ColumnModel model = (ColumnModel) node.getData();
if (model.getProperty().equals(property)) {
root.getChildren().remove(node);
break;
}
}
}
public void tableToTree() {
Map<String, String> params = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap();
int colIndex = Integer.parseInt(params.get("colIndex"));
//remove from table
ColumnModel model = this.columns.remove(colIndex);
//add to nodes
TreeNode property = new DefaultTreeNode("column", model, availableColumns.getChildren().get(0));
}
public List<Product> getProducts() {
return products;
}
public List<ColumnModel> getColumns() {
return columns;
}
public TreeNode getAvailableColumns() {
return availableColumns;
}
public void setService(ProductService service) {
this.service = service;
}
public static class ColumnModel implements Serializable {
private String header;
private String property;
public ColumnModel(String header, String property) {
this.header = header;
this.property = property;
}
public String getHeader() {
return header;
}
public String getProperty() {
return property;
}
}
}
@Named
@ApplicationScoped
public class ProductService {
private List<Product> products;
@PostConstruct
public void init() {
products = new ArrayList<>();
products.add(new Product(1000, "f230fh0g3", "Bamboo Watch", "Product Description", "bamboo-watch.jpg", 65,
"Accessories", 24, InventoryStatus.INSTOCK, 5));
products.add(new Product(1001, "nvklal433", "Black Watch", "Product Description", "black-watch.jpg", 72,
"Accessories", 61, InventoryStatus.INSTOCK, 4));
products.add(new Product(1002, "zz21cz3c1", "Blue Band", "Product Description", "blue-band.jpg", 79,
"Fitness", 2, InventoryStatus.LOWSTOCK, 3));
products.add(new Product(1003, "244wgerg2", "Blue T-Shirt", "Product Description", "blue-t-shirt.jpg", 29,
"Clothing", 25, InventoryStatus.INSTOCK, 5));
products.add(new Product(1004, "h456wer53", "Bracelet", "Product Description", "bracelet.jpg", 15,
"Accessories", 73, InventoryStatus.INSTOCK, 4));
products.add(new Product(1005, "av2231fwg", "Brown Purse", "Product Description", "brown-purse.jpg", 120,
"Accessories", 0, InventoryStatus.OUTOFSTOCK, 4));
products.add(new Product(1006, "bib36pfvm", "Chakra Bracelet", "Product Description", "chakra-bracelet.jpg", 32,
"Accessories", 5, InventoryStatus.LOWSTOCK, 3));
products.add(new Product(1007, "mbvjkgip5", "Galaxy Earrings", "Product Description", "galaxy-earrings.jpg", 34,
"Accessories", 23, InventoryStatus.INSTOCK, 5));
products.add(new Product(1008, "vbb124btr", "Game Controller", "Product Description", "game-controller.jpg", 99,
"Electronics", 2, InventoryStatus.LOWSTOCK, 4));
products.add(new Product(1009, "cm230f032", "Gaming Set", "Product Description", "gaming-set.jpg", 299,
"Electronics", 63, InventoryStatus.INSTOCK, 3));
products.add(new Product(1010, "plb34234v", "Gold Phone Case", "Product Description", "gold-phone-case.jpg", 24,
"Accessories", 0, InventoryStatus.OUTOFSTOCK, 4));
products.add(new Product(1011, "4920nnc2d", "Green Earbuds", "Product Description", "green-earbuds.jpg", 89,
"Electronics", 23, InventoryStatus.INSTOCK, 4));
products.add(new Product(1012, "250vm23cc", "Green T-Shirt", "Product Description", "green-t-shirt.jpg", 49,
"Clothing", 74, InventoryStatus.INSTOCK, 5));
products.add(new Product(1013, "fldsmn31b", "Grey T-Shirt", "Product Description", "grey-t-shirt.jpg", 48,
"Clothing", 0, InventoryStatus.OUTOFSTOCK, 3));
products.add(new Product(1014, "waas1x2as", "Headphones", "Product Description", "headphones.jpg", 175,
"Electronics", 8, InventoryStatus.LOWSTOCK, 5));
products.add(new Product(1015, "vb34btbg5", "Light Green T-Shirt", "Product Description", "light-green-t-shirt.jpg", 49,
"Clothing", 34, InventoryStatus.INSTOCK, 4));
products.add(new Product(1016, "k8l6j58jl", "Lime Band", "Product Description", "lime-band.jpg", 79,
"Fitness", 12, InventoryStatus.INSTOCK, 3));
products.add(new Product(1017, "v435nn85n", "Mini Speakers", "Product Description", "mini-speakers.jpg", 85,
"Clothing", 42, InventoryStatus.INSTOCK, 4));
products.add(new Product(1018, "09zx9c0zc", "Painted Phone Case", "Product Description", "painted-phone-case.jpg", 56,
"Accessories", 41, InventoryStatus.INSTOCK, 5));
products.add(new Product(1019, "mnb5mb2m5", "Pink Band", "Product Description", "pink-band.jpg", 79,
"Fitness", 63, InventoryStatus.INSTOCK, 4));
products.add(new Product(1020, "r23fwf2w3", "Pink Purse", "Product Description", "pink-purse.jpg", 110,
"Accessories", 0, InventoryStatus.OUTOFSTOCK, 4));
products.add(new Product(1021, "pxpzczo23", "Purple Band", "Product Description", "purple-band.jpg", 79,
"Fitness", 6, InventoryStatus.LOWSTOCK, 3));
products.add(new Product(1022, "2c42cb5cb", "Purple Gemstone Necklace", "Product Description", "purple-gemstone-necklace.jpg", 45,
"Accessories", 62, InventoryStatus.INSTOCK, 4));
products.add(new Product(1023, "5k43kkk23", "Purple T-Shirt", "Product Description", "purple-t-shirt.jpg", 49,
"Clothing", 2, InventoryStatus.LOWSTOCK, 5));
products.add(new Product(1024, "lm2tny2k4", "Shoes", "Product Description", "shoes.jpg", 64,
"Clothing", 0, InventoryStatus.INSTOCK, 4));
products.add(new Product(1025, "nbm5mv45n", "Sneakers", "Product Description", "sneakers.jpg", 78,
"Clothing", 52, InventoryStatus.INSTOCK, 4));
products.add(new Product(1026, "zx23zc42c", "Teal T-Shirt", "Product Description", "teal-t-shirt.jpg", 49,
"Clothing", 3, InventoryStatus.LOWSTOCK, 3));
products.add(new Product(1027, "acvx872gc", "Yellow Earbuds", "Product Description", "yellow-earbuds.jpg", 89,
"Electronics", 35, InventoryStatus.INSTOCK, 3));
products.add(new Product(1028, "tx125ck42", "Yoga Mat", "Product Description", "yoga-mat.jpg", 20,
"Fitness", 15, InventoryStatus.INSTOCK, 5));
products.add(new Product(1029, "gwuby345v", "Yoga Set", "Product Description", "yoga-set.jpg", 20,
"Fitness", 25, InventoryStatus.INSTOCK, 8));
}
public List<Product> getProducts() {
return new ArrayList<>(products);
}
public List<Product> getProducts(int size) {
if (size > products.size()) {
Random rand = new Random();
List<Product> randomList = new ArrayList<>();
for (int i = 0; i < size; i++) {
int randomIndex = rand.nextInt(products.size());
randomList.add(products.get(randomIndex));
}
return randomList;
}
else {
return new ArrayList<>(products.subList(0, size));
}
}
public List<Product> getClonedProducts(int size) {
List<Product> results = new ArrayList<>();
List<Product> originals = getProducts(size);
for (Product original : originals) {
results.add(original.clone());
}
// make sure to have unique codes
for (Product product : results) {
product.setCode(UUID.randomUUID().toString().replace("-", "").substring(0, 8));
}
return results;
}
}