This example shows how to implement lazy loading of child nodes - which is essential for big models.
<div class="card">
<h:form id="form">
<p:growl id="messages" showDetail="true"/>
<p:tree value="#{treeLazyLoadingView.root}" var="node" dynamic="true">
<p:treeNode>
<h:outputText value="#{node.name}"/>
</p:treeNode>
</p:tree>
</h:form>
</div>
@Named("treeLazyLoadingView")
@ViewScoped
public class LazyLoadingView implements Serializable {
private TreeNode root;
@PostConstruct
public void init() {
FacesContext context = FacesContext.getCurrentInstance();
FileInfo path = new FileInfo(context.getExternalContext().getRealPath("/"), true);
root = new LazyLoadingTreeNode(path, (folder) -> listFiles(folder));
}
public static List<FileInfo> listFiles(String parentFolder) {
File[] files = new File(parentFolder).listFiles();
if (files == null) {
return new ArrayList<>();
}
List<FileInfo> result = new ArrayList<>();
for (File file : files) {
result.add(new FileInfo(file.getAbsolutePath(), file.isDirectory()));
}
return result;
}
public TreeNode getRoot() {
return root;
}
}
public class FileInfo implements Serializable {
private String path;
private String name;
private boolean directory;
public FileInfo(String path, boolean directory) {
this.path = path;
if (this.path.equals(File.separator)) {
this.name = this.path;
}
else {
String[] parts = path.split(File.separator.equals("\\") ? "\\\\" : File.separator);
this.name = parts[parts.length - 1];
}
this.directory = directory;
}
public String getPath() {
return path;
}
public String getName() {
return name;
}
public boolean isDirectory() {
return directory;
}
@Override
public String toString() {
return path + " / " + name;
}
}
public class LazyLoadingTreeNode extends DefaultTreeNode<FileInfo> {
private Function<String, List<FileInfo>> loadFunction;
private boolean lazyLoaded;
public LazyLoadingTreeNode(FileInfo data, Function<String, List<FileInfo>> loadFunction) {
super(data);
this.loadFunction = loadFunction;
}
@Override
public List<TreeNode<FileInfo>> getChildren() {
if (isLeaf()) {
return Collections.emptyList();
}
lazyLoad();
return super.getChildren();
}
@Override
public int getChildCount() {
if (isLeaf()) {
return 0;
}
lazyLoad();
return super.getChildCount();
}
@Override
public boolean isLeaf() {
return !getData().isDirectory();
}
private void lazyLoad() {
if (!lazyLoaded) {
lazyLoaded = true;
String parentId = ((FileInfo) getData()).getPath();
List<LazyLoadingTreeNode> childNodes = loadFunction.apply(parentId).stream()
.map(f -> new LazyLoadingTreeNode(f, loadFunction)).collect(Collectors.toList());
super.getChildren().addAll(childNodes);
}
}
@Override
protected List<TreeNode<FileInfo>> initChildren() {
return new LazyLoadingTreeNodeChildren(this);
}
public static class LazyLoadingTreeNodeChildren extends TreeNodeChildren<FileInfo> {
public LazyLoadingTreeNodeChildren(LazyLoadingTreeNode parent) {
super(parent);
}
@Override
protected void updateRowKeys(TreeNode<?> node) {
if (((LazyLoadingTreeNode) node).lazyLoaded) {
super.updateRowKeys(node);
}
}
@Override
protected void updateRowKeys(int index, TreeNode<?> node) {
if (((LazyLoadingTreeNode) node).lazyLoaded) {
super.updateRowKeys(index, node);
}
}
@Override
protected void updateRowKeys(TreeNode<?> node, TreeNode<?> childNode, int i) {
if (((LazyLoadingTreeNode) node).lazyLoaded) {
super.updateRowKeys(node, childNode, i);
}
}
}
}