Встроенные декларативные теги JSF плохо подходят для обработки рекурсии такого рода.JSF создает дерево компонентов с сохранением состояния, которое сохраняется между запросами.Если представление восстанавливается в последующем запросе, состояние представления может не отражать изменения в модели.
Я бы предпочел императивный подход.У меня есть два варианта, как я вижу:
- Используйте атрибут
binding
, чтобы связать элемент управления (например, некоторую форму панели) с базовым компонентом, который предоставляет экземпляр UIComponent
и его дочерние элементы -Вы пишете код для создания экземпляра UIComponent
и добавляете детей, которых хотите.См. Спецификацию для binding
контракта атрибута. - Напишите пользовательский элемент управления, реализуя некоторые из: a
UIComponent
;а Renderer
;обработчик тега;Файлы метаданных (удаляйте по необходимости - вы делаете некоторые или все из них в зависимости от того, что вы делаете, как и в какой версии JSF).
Возможно, другой вариант - выбратьдо стороннего элемента управления, который уже делает это.
ОБНОВЛЕНИЕ: Если кто-то использует очень полезную библиотеку OmniFaces (вам следует, если вы этого не сделаетеуже), есть <o:tree>
, который не имеет генерации html, но был специально разработан для поддержки таких случаев использования, как этот.
<o:tree value="#{bean.treeModel}" var="item" varNode="node">
<o:treeNode>
<ul>
<o:treeNodeItem>
<li>
#{node.index} #{item.someProperty}
<o:treeInsertChildren />
</li>
</o:treeNodeItem>
</ul>
</o:treeNode>
</o:tree>
РЕДАКТИРОВАТЬ:
Вот подход, основанный на модели, который не включает в себя написание пользовательских компонентов или деревьев компонентов, созданных на основе бина.Это некрасиво.
Представление Facelets:
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets">
<h:head><title>Facelet Tree</title></h:head>
<h:body>
<ul>
<ui:repeat value="#{tree.treeNodes}" var="node">
<h:outputText rendered="#{node.firstChild}"
value="<ul>" escape="false" />
<li>
<h:outputText value="#{node.value}" />
</li>
<ui:repeat rendered="#{node.lastChild and empty node.kids}"
value="#{node.lastChildLineage}" var="ignore">
<h:outputText
value="</ul>" escape="false" />
</ui:repeat>
</ui:repeat>
</ul>
</h:body>
</html>
Управляемый компонент:
@javax.faces.bean.ManagedBean(name = "tree")
@javax.faces.bean.RequestScoped
public class Tree {
private Node<String> root = new Node(null, "JSF Stuff");
@PostConstruct
public void initData() {
root.getKids().add(new Node(root, "Chapter One"));
root.getKids().add(new Node(root, "Chapter Two"));
root.getKids().add(new Node(root, "Chapter Three"));
Node<String> chapter2 = root.getKids().get(1);
chapter2.getKids().add(new Node(chapter2, "Section A"));
chapter2.getKids().add(new Node(chapter2, "Section B"));
}
public List<Node<String>> getTreeNodes() {
return walk(new ArrayList<Node<String>>(), root);
}
private List<Node<String>> walk(List<Node<String>> list, Node<String> node) {
list.add(node);
for(Node<String> kid : node.getKids()) {
walk(list, kid);
}
return list;
}
}
Узел дерева:
public class Node<T> {
private T value;
private Node<T> parent;
private LinkedList<Node<T>> kids = new LinkedList<>();
public Node(Node<T> parent, T value) {
this.parent = parent;
this.value = value;
}
public List<Node<T>> getKids() {return kids;}
public T getValue() { return value; }
public boolean getHasParent() { return parent != null; }
public boolean isFirstChild() {
return parent != null && parent.kids.peekFirst() == this;
}
public boolean isLastChild() {
return parent != null && parent.kids.peekLast() == this;
}
public List<Node> getLastChildLineage() {
Node node = this;
List<Node> lineage = new ArrayList<>();
while(node.isLastChild()) {
lineage.add(node);
node = node.parent;
}
return lineage;
}
}
Вывод:
* JSF Stuff
o Chapter One
o Chapter Two
+ Section A
+ Section B
o Chapter Three
Я бы все равно прикусил пулю и написал пользовательский древовидный элемент управления.