How to add a custom composite component dynamically in JSF?

I’m trying to add two components dynamically to the page: “selectOneTreeList.xhtml” and “selectManyTreeList.xhtml”. When I add them directly in the XHTML, they work correctly. However, when added dynamically, with “selectOneTreeList”, nodes can be selected, but if anything is entered in the search field, all nodes disappear. With “selectManyTreeList”, the search field issue remains, and it’s also not possible to select any elements.

I created a small project to demonstrate the issue: GitHub

But you can see the main code below:

In all cases, when searching in both components and selecting an item in selectManyTreeList, there is one error:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>2024-08-07 12:03:07.729 ERROR 417419 --- [io-55557-exec-6] j.e.resource.webcontainer.jsf.context : javax.faces.FacesException: Unsupported tree node type:default
at org.primefaces.component.tree.Tree.getUITreeNodeByType(Tree.java:116)
at org.primefaces.component.tree.TreeRenderer.encodeTreeNode(TreeRenderer.java:663)
at org.primefaces.component.tree.TreeRenderer.encodeTreeNodeChildren(TreeRenderer.java:806)
at org.primefaces.component.tree.TreeRenderer.encodeVerticalTree(TreeRenderer.java:405)
at org.primefaces.component.tree.TreeRenderer.encodeMarkup(TreeRenderer.java:344)
at org.primefaces.component.tree.TreeRenderer.encodeEnd(TreeRenderer.java:257)
at javax.faces.component.UIComponentBase.encodeEnd(UIComponentBase.java:949)
at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1912)
at com.sun.faces.context.PartialViewContextImpl$PhaseAwareVisitCallback.visit(PartialViewContextImpl.java:638)
at com.sun.faces.component.visit.PartialVisitContext.invokeVisitCallback(PartialVisitContext.java:183)
at org.primefaces.component.api.UITree.visitTree(UITree.java:823)
at javax.faces.component.UIComponent.visitTree(UIComponent.java:1747)
at javax.faces.component.UIComponent.visitTree(UIComponent.java:1747)
at javax.faces.component.UIComponent.visitTree(UIComponent.java:1747)
at javax.faces.component.UIComponent.visitTree(UIComponent.java:1747)
at javax.faces.component.UIForm.visitTree(UIForm.java:395)
at javax.faces.component.UIComponent.visitTree(UIComponent.java:1747)
at javax.faces.component.UIComponent.visitTree(UIComponent.java:1747)
at com.sun.faces.context.PartialViewContextImpl.processComponents(PartialViewContextImpl.java:423)
at com.sun.faces.context.PartialViewContextImpl.processPartial(PartialViewContextImpl.java:342)
at org.primefaces.context.PrimePartialViewContext.processPartial(PrimePartialViewContext.java:65)
at javax.faces.component.UIViewRoot.encodeChildren(UIViewRoot.java:1124)
at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1905)
at com.sun.faces.application.view.FaceletViewHandlingStrategy.renderView(FaceletViewHandlingStrategy.java:465)
at com.sun.faces.application.view.MultiViewHandler.renderView(MultiViewHandler.java:194)
at javax.faces.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:151)
at com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:126)
at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:100)
at com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:223)
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:671)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at com.spring.jsf.spring_jsf.filter.CorsFilter.doFilterInternal(CorsFilter.java:26)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:540)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:382)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:895)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1732)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)
at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:748)
</code>
<code>2024-08-07 12:03:07.729 ERROR 417419 --- [io-55557-exec-6] j.e.resource.webcontainer.jsf.context : javax.faces.FacesException: Unsupported tree node type:default at org.primefaces.component.tree.Tree.getUITreeNodeByType(Tree.java:116) at org.primefaces.component.tree.TreeRenderer.encodeTreeNode(TreeRenderer.java:663) at org.primefaces.component.tree.TreeRenderer.encodeTreeNodeChildren(TreeRenderer.java:806) at org.primefaces.component.tree.TreeRenderer.encodeVerticalTree(TreeRenderer.java:405) at org.primefaces.component.tree.TreeRenderer.encodeMarkup(TreeRenderer.java:344) at org.primefaces.component.tree.TreeRenderer.encodeEnd(TreeRenderer.java:257) at javax.faces.component.UIComponentBase.encodeEnd(UIComponentBase.java:949) at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1912) at com.sun.faces.context.PartialViewContextImpl$PhaseAwareVisitCallback.visit(PartialViewContextImpl.java:638) at com.sun.faces.component.visit.PartialVisitContext.invokeVisitCallback(PartialVisitContext.java:183) at org.primefaces.component.api.UITree.visitTree(UITree.java:823) at javax.faces.component.UIComponent.visitTree(UIComponent.java:1747) at javax.faces.component.UIComponent.visitTree(UIComponent.java:1747) at javax.faces.component.UIComponent.visitTree(UIComponent.java:1747) at javax.faces.component.UIComponent.visitTree(UIComponent.java:1747) at javax.faces.component.UIForm.visitTree(UIForm.java:395) at javax.faces.component.UIComponent.visitTree(UIComponent.java:1747) at javax.faces.component.UIComponent.visitTree(UIComponent.java:1747) at com.sun.faces.context.PartialViewContextImpl.processComponents(PartialViewContextImpl.java:423) at com.sun.faces.context.PartialViewContextImpl.processPartial(PartialViewContextImpl.java:342) at org.primefaces.context.PrimePartialViewContext.processPartial(PrimePartialViewContext.java:65) at javax.faces.component.UIViewRoot.encodeChildren(UIViewRoot.java:1124) at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1905) at com.sun.faces.application.view.FaceletViewHandlingStrategy.renderView(FaceletViewHandlingStrategy.java:465) at com.sun.faces.application.view.MultiViewHandler.renderView(MultiViewHandler.java:194) at javax.faces.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:151) at com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:126) at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:100) at com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:223) at javax.faces.webapp.FacesServlet.service(FacesServlet.java:671) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) at com.spring.jsf.spring_jsf.filter.CorsFilter.doFilterInternal(CorsFilter.java:26) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:540) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357) at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:382) at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:895) at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1732) at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) at java.lang.Thread.run(Thread.java:748) </code>
2024-08-07 12:03:07.729 ERROR 417419 --- [io-55557-exec-6] j.e.resource.webcontainer.jsf.context    : javax.faces.FacesException: Unsupported tree node type:default
    at org.primefaces.component.tree.Tree.getUITreeNodeByType(Tree.java:116)
    at org.primefaces.component.tree.TreeRenderer.encodeTreeNode(TreeRenderer.java:663)
    at org.primefaces.component.tree.TreeRenderer.encodeTreeNodeChildren(TreeRenderer.java:806)
    at org.primefaces.component.tree.TreeRenderer.encodeVerticalTree(TreeRenderer.java:405)
    at org.primefaces.component.tree.TreeRenderer.encodeMarkup(TreeRenderer.java:344)
    at org.primefaces.component.tree.TreeRenderer.encodeEnd(TreeRenderer.java:257)
    at javax.faces.component.UIComponentBase.encodeEnd(UIComponentBase.java:949)
    at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1912)
    at com.sun.faces.context.PartialViewContextImpl$PhaseAwareVisitCallback.visit(PartialViewContextImpl.java:638)
    at com.sun.faces.component.visit.PartialVisitContext.invokeVisitCallback(PartialVisitContext.java:183)
    at org.primefaces.component.api.UITree.visitTree(UITree.java:823)
    at javax.faces.component.UIComponent.visitTree(UIComponent.java:1747)
    at javax.faces.component.UIComponent.visitTree(UIComponent.java:1747)
    at javax.faces.component.UIComponent.visitTree(UIComponent.java:1747)
    at javax.faces.component.UIComponent.visitTree(UIComponent.java:1747)
    at javax.faces.component.UIForm.visitTree(UIForm.java:395)
    at javax.faces.component.UIComponent.visitTree(UIComponent.java:1747)
    at javax.faces.component.UIComponent.visitTree(UIComponent.java:1747)
    at com.sun.faces.context.PartialViewContextImpl.processComponents(PartialViewContextImpl.java:423)
    at com.sun.faces.context.PartialViewContextImpl.processPartial(PartialViewContextImpl.java:342)
    at org.primefaces.context.PrimePartialViewContext.processPartial(PrimePartialViewContext.java:65)
    at javax.faces.component.UIViewRoot.encodeChildren(UIViewRoot.java:1124)
    at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1905)
    at com.sun.faces.application.view.FaceletViewHandlingStrategy.renderView(FaceletViewHandlingStrategy.java:465)
    at com.sun.faces.application.view.MultiViewHandler.renderView(MultiViewHandler.java:194)
    at javax.faces.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:151)
    at com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:126)
    at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:100)
    at com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:223)
    at javax.faces.webapp.FacesServlet.service(FacesServlet.java:671)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
    at com.spring.jsf.spring_jsf.filter.CorsFilter.doFilterInternal(CorsFilter.java:26)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:540)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357)
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:382)
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:895)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1732)
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
    at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)
    at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:748)

Template selectOneTreeList.xhtml:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>
<cc:interface componentType="selectOneTreeList">
<cc:attribute name="value" required="true"
shortDescription="Value from NodeDTO"/>
<cc:attribute name="items" type="java.util.List" required="true"
shortDescription="List items, should implements NodeDTO"/>
<cc:attribute name="disabled" type="boolean" required="false" default="false"/>
<cc:attribute name="update" type="java.lang.String" required="false"
shortDescription="Component(s) id to update"/>
<cc:attribute name="styleClass" type="java.lang.String" required="false"
shortDescription="Style class of the component"/>
</cc:interface>
<cc:implementation>
<div id="#{cc.clientId}" class="select-tree-list #{cc.attrs.disabled ? 'ui-state-disabled' : ''} #{cc.attrs.styleClass}">
<div jsf:id="label-container" class="p-d-flex p-px-2">
<div class="p-col p-p-2">
<h:outputText id="label"
value="#{cc.selection.data.name}"
styleClass="select-tree-list-label"/>
</div>
<div class="p-p-2">
<i class="pi pi-chevron-down"/>
</div>
</div>
<p:overlayPanel
for="label-container"
widgetVar="#{cc.widgetVar}_overlay"
styleClass="select-tree-list-overlay"
rendered="#{!cc.attrs.disabled}"
appendTo="@form">
<!--@elvariable id="node" type="com.spring.jsf.spring_jsf.dto.NodeDTO"-->
<p:tree var="node"
binding="#{cc.tree}"
value="#{cc.rootNode}"
filterBy="#{node.name}"
filterMatchMode="contains"
selectionMode="single">
<p:ajax event="select" update="@parent:label #{cc.attrs.update}"
oncomplete="PF('#{cc.widgetVar}_overlay').hide()"
listener="#{cc.onNodeSelect}"/>
<p:treeNode>
<h:outputText value="#{node.name}"/>
</p:treeNode>
</p:tree>
</p:overlayPanel>
</div>
</cc:implementation>
</code>
<code> <cc:interface componentType="selectOneTreeList"> <cc:attribute name="value" required="true" shortDescription="Value from NodeDTO"/> <cc:attribute name="items" type="java.util.List" required="true" shortDescription="List items, should implements NodeDTO"/> <cc:attribute name="disabled" type="boolean" required="false" default="false"/> <cc:attribute name="update" type="java.lang.String" required="false" shortDescription="Component(s) id to update"/> <cc:attribute name="styleClass" type="java.lang.String" required="false" shortDescription="Style class of the component"/> </cc:interface> <cc:implementation> <div id="#{cc.clientId}" class="select-tree-list #{cc.attrs.disabled ? 'ui-state-disabled' : ''} #{cc.attrs.styleClass}"> <div jsf:id="label-container" class="p-d-flex p-px-2"> <div class="p-col p-p-2"> <h:outputText id="label" value="#{cc.selection.data.name}" styleClass="select-tree-list-label"/> </div> <div class="p-p-2"> <i class="pi pi-chevron-down"/> </div> </div> <p:overlayPanel for="label-container" widgetVar="#{cc.widgetVar}_overlay" styleClass="select-tree-list-overlay" rendered="#{!cc.attrs.disabled}" appendTo="@form"> <!--@elvariable id="node" type="com.spring.jsf.spring_jsf.dto.NodeDTO"--> <p:tree var="node" binding="#{cc.tree}" value="#{cc.rootNode}" filterBy="#{node.name}" filterMatchMode="contains" selectionMode="single"> <p:ajax event="select" update="@parent:label #{cc.attrs.update}" oncomplete="PF('#{cc.widgetVar}_overlay').hide()" listener="#{cc.onNodeSelect}"/> <p:treeNode> <h:outputText value="#{node.name}"/> </p:treeNode> </p:tree> </p:overlayPanel> </div> </cc:implementation> </code>

    <cc:interface componentType="selectOneTreeList">
        <cc:attribute name="value" required="true"
                      shortDescription="Value from NodeDTO"/>
        <cc:attribute name="items" type="java.util.List" required="true"
                      shortDescription="List items, should implements NodeDTO"/>
        <cc:attribute name="disabled" type="boolean" required="false" default="false"/>
        <cc:attribute name="update" type="java.lang.String" required="false"
                      shortDescription="Component(s) id to update"/>
        <cc:attribute name="styleClass" type="java.lang.String" required="false"
                      shortDescription="Style class of the component"/>
    </cc:interface>

    <cc:implementation>

        <div id="#{cc.clientId}" class="select-tree-list #{cc.attrs.disabled ? 'ui-state-disabled' : ''} #{cc.attrs.styleClass}">
            <div jsf:id="label-container" class="p-d-flex p-px-2">
                <div class="p-col p-p-2">
                    <h:outputText id="label"
                                  value="#{cc.selection.data.name}"
                                  styleClass="select-tree-list-label"/>
                </div>
                <div class="p-p-2">
                    <i class="pi pi-chevron-down"/>
                </div>
            </div>

            <p:overlayPanel
                    for="label-container"
                    widgetVar="#{cc.widgetVar}_overlay"
                    styleClass="select-tree-list-overlay"
                    rendered="#{!cc.attrs.disabled}"
                    appendTo="@form">
                <!--@elvariable id="node" type="com.spring.jsf.spring_jsf.dto.NodeDTO"-->
                <p:tree var="node"
                        binding="#{cc.tree}"
                        value="#{cc.rootNode}"
                        filterBy="#{node.name}"
                        filterMatchMode="contains"
                        selectionMode="single">
                    <p:ajax event="select" update="@parent:label #{cc.attrs.update}"
                            oncomplete="PF('#{cc.widgetVar}_overlay').hide()"
                            listener="#{cc.onNodeSelect}"/>
                    <p:treeNode>
                        <h:outputText value="#{node.name}"/>
                    </p:treeNode>
                </p:tree>
            </p:overlayPanel>
        </div>
    </cc:implementation>

Class SelectOneTreeList:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>@FacesComponent("selectOneTreeList")
@ResourceDependency(library = "components", name = "select-tree-list.css")
public class SelectOneTreeList extends UIInput implements NamingContainer {
private Tree tree;
enum PropertyKeys {
rootNode,
items,
disabled,
update
}
private Map<Object, Object> attrs = new HashMap<>();
@Override
public String getFamily() {
return UINamingContainer.COMPONENT_FAMILY;
}
@Override
public void encodeBegin(FacesContext context) throws IOException {
TreeNode rootNode = new DefaultTreeNode();
setRootNode(rootNode);
List<TreeNode> nodes = NodeUtils.createTreeNodes(rootNode, getItems(), DefaultTreeNode::new);
TreeNode selected = Optional.ofNullable(getValue())
.flatMap(v -> NodeUtils.findNode(v, nodes))
.orElse(null);
selectNode(selected);
NodeUtils.expandParents(selected);
super.encodeBegin(context);
}
private void selectNode(TreeNode treeNode) {
tree.setSelection(treeNode);
if (treeNode != null) {
treeNode.setSelected(true);
}
}
@Override
public Object getSubmittedValue() {
return NodeUtils.getNodeValue(getSelection())
.orElse(null);
}
@SuppressWarnings("unchecked")
private Collection<NodeDTO> getItems() {
return (Collection<NodeDTO>) getStateHelper()
.eval(PropertyKeys.items, Collections.EMPTY_LIST);
}
public TreeNode getSelection() {
return (TreeNode) tree.getSelection();
}
public Tree getTree() {
return tree;
}
public void setTree(Tree tree) {
this.tree = tree;
}
public TreeNode getRootNode() {
return (TreeNode) getStateHelper().eval(PropertyKeys.rootNode);
}
public void setRootNode(TreeNode rootNode) {
getStateHelper().put(PropertyKeys.rootNode, rootNode);
}
public String getWidgetVar() {
return "widget_" + getClientId().replace(":", "_");
}
public void onNodeSelect(NodeSelectEvent event) {
ValueExpression ve = getValueExpression("value");
ve.setValue(event.getFacesContext().getELContext(), getSubmittedValue());
}
public Map<Object, Object> getAttrs() {
return attrs;
}
public void setAttrs(Map<Object, Object> attrs) {
this.attrs = attrs;
}
</code>
<code>@FacesComponent("selectOneTreeList") @ResourceDependency(library = "components", name = "select-tree-list.css") public class SelectOneTreeList extends UIInput implements NamingContainer { private Tree tree; enum PropertyKeys { rootNode, items, disabled, update } private Map<Object, Object> attrs = new HashMap<>(); @Override public String getFamily() { return UINamingContainer.COMPONENT_FAMILY; } @Override public void encodeBegin(FacesContext context) throws IOException { TreeNode rootNode = new DefaultTreeNode(); setRootNode(rootNode); List<TreeNode> nodes = NodeUtils.createTreeNodes(rootNode, getItems(), DefaultTreeNode::new); TreeNode selected = Optional.ofNullable(getValue()) .flatMap(v -> NodeUtils.findNode(v, nodes)) .orElse(null); selectNode(selected); NodeUtils.expandParents(selected); super.encodeBegin(context); } private void selectNode(TreeNode treeNode) { tree.setSelection(treeNode); if (treeNode != null) { treeNode.setSelected(true); } } @Override public Object getSubmittedValue() { return NodeUtils.getNodeValue(getSelection()) .orElse(null); } @SuppressWarnings("unchecked") private Collection<NodeDTO> getItems() { return (Collection<NodeDTO>) getStateHelper() .eval(PropertyKeys.items, Collections.EMPTY_LIST); } public TreeNode getSelection() { return (TreeNode) tree.getSelection(); } public Tree getTree() { return tree; } public void setTree(Tree tree) { this.tree = tree; } public TreeNode getRootNode() { return (TreeNode) getStateHelper().eval(PropertyKeys.rootNode); } public void setRootNode(TreeNode rootNode) { getStateHelper().put(PropertyKeys.rootNode, rootNode); } public String getWidgetVar() { return "widget_" + getClientId().replace(":", "_"); } public void onNodeSelect(NodeSelectEvent event) { ValueExpression ve = getValueExpression("value"); ve.setValue(event.getFacesContext().getELContext(), getSubmittedValue()); } public Map<Object, Object> getAttrs() { return attrs; } public void setAttrs(Map<Object, Object> attrs) { this.attrs = attrs; } </code>
@FacesComponent("selectOneTreeList")
@ResourceDependency(library = "components", name = "select-tree-list.css")
public class SelectOneTreeList extends UIInput implements NamingContainer {

    private Tree tree;

    enum PropertyKeys {
        rootNode,
        items,
        disabled,
        update
    }

    private Map<Object, Object> attrs = new HashMap<>();

    @Override
    public String getFamily() {
        return UINamingContainer.COMPONENT_FAMILY;
    }

    @Override
    public void encodeBegin(FacesContext context) throws IOException {
        TreeNode rootNode = new DefaultTreeNode();
        setRootNode(rootNode);

        List<TreeNode> nodes = NodeUtils.createTreeNodes(rootNode, getItems(), DefaultTreeNode::new);

        TreeNode selected = Optional.ofNullable(getValue())
                .flatMap(v -> NodeUtils.findNode(v, nodes))
                .orElse(null);
        selectNode(selected);
        NodeUtils.expandParents(selected);
        super.encodeBegin(context);
    }

    private void selectNode(TreeNode treeNode) {
        tree.setSelection(treeNode);
        if (treeNode != null) {
            treeNode.setSelected(true);
        }
    }

    @Override
    public Object getSubmittedValue() {
        return NodeUtils.getNodeValue(getSelection())
                .orElse(null);
    }

    @SuppressWarnings("unchecked")
    private Collection<NodeDTO> getItems() {
        return (Collection<NodeDTO>) getStateHelper()
                .eval(PropertyKeys.items, Collections.EMPTY_LIST);
    }

    public TreeNode getSelection() {
        return (TreeNode) tree.getSelection();
    }

    public Tree getTree() {
        return tree;
    }

    public void setTree(Tree tree) {
        this.tree = tree;
    }

    public TreeNode getRootNode() {
        return (TreeNode) getStateHelper().eval(PropertyKeys.rootNode);
    }

    public void setRootNode(TreeNode rootNode) {
        getStateHelper().put(PropertyKeys.rootNode, rootNode);
    }

    public String getWidgetVar() {
        return "widget_" + getClientId().replace(":", "_");
    }

    public void onNodeSelect(NodeSelectEvent event) {
        ValueExpression ve = getValueExpression("value");
        ve.setValue(event.getFacesContext().getELContext(), getSubmittedValue());
    }

    public Map<Object, Object> getAttrs() {
        return attrs;
    }

    public void setAttrs(Map<Object, Object> attrs) {
        this.attrs = attrs;
    }

Template selectManyTreeList.xhtml:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>
<cc:interface componentType="selectManyTreeList">
<cc:attribute name="value" type="java.util.Collection" required="true"
shortDescription="Collection of selected NodeDTO's values. Must not be null!"/>
<cc:attribute name="items" type="java.util.List" required="true"
shortDescription="List items, should contains NodeDTO"/>
<cc:attribute name="disabled" type="boolean" required="false"
default="false"/>
<!--TODO: сделать через cc:clientBehavior-->
<cc:attribute name="update" type="java.lang.String" required="false"
shortDescription="Component(s) id to update"/>
<cc:attribute name="styleClass" type="java.lang.String" required="false"
shortDescription="Style class of the component"/>
<cc:attribute name="propagateSelectionUp" type="java.lang.Boolean" required="false"
default="true" shortDescription="Select children of selected node"/>
<cc:attribute name="propagateSelectionDown" type="java.lang.Boolean" required="false"
default="true" shortDescription="Select parent if all children selected"/>
<cc:attribute name="highlightBranchChips" type="java.lang.Boolean" required="false"
default="false" shortDescription="Highlight chips for nodes, that have child nodes"/>
<cc:attribute name="onChangeSelection" method-signature="void listener(java.util.Collection)" required="false"
shortDescription="An application select/unselect listener"/>
</cc:interface>
<cc:implementation>
<div id="#{cc.clientId}"
class="#{cc.attrs.styleClass} select-tree-list #{cc.attrs.disabled ? 'ui-state-disabled':''}">
<div class="p-px-2 selected-values-area">
<div jsf:id="selected-values"
class="p-col p-p-2 select-tree-list-chips">
<ui:repeat value="#{cc.selections}" var="node">
<!--@elvariable id="node" type="com.spring.jsf.spring_jsf.dto.NodeDTO"-->
<p:chip label="#{node.data.name}"
styleClass="#{cc.attrs.highlightBranchChips and node.data.hasChildren ? 'branchChip' : ''}"
removable="#{not cc.attrs.disabled}"
removeIcon="pi pi-times">
<p:ajax event="close"
listener="#{cc.onRemoveNode(node)}"/>
</p:chip>
</ui:repeat>
</div>
<div jsf:id="clickable-area" class="clickable-area"></div>
<div class="p-p-2 chevron">
<i class="pi pi-chevron-down"/>
</div>
</div>
<p:overlayPanel
for="clickable-area"
styleClass="select-tree-list-overlay"
appendTo="@form">
<!--@elvariable id="node" type="com.spring.jsf.spring_jsf.dto.NodeDTO"-->
<p:tree var="node"
id="tree"
widgetVar="#{cc.widgetVar}_tree"
binding="#{cc.tree}"
value="#{cc.rootNode}"
filterBy="#{node.name}"
filterMatchMode="contains"
selectionMode="checkbox"
propagateSelectionUp="#{cc.attrs.propagateSelectionUp}"
propagateSelectionDown="#{cc.attrs.propagateSelectionDown}">
<p:ajax event="select"
update="#{cc.clientId}:selected-values #{cc.clientId}:tree #{cc.attrs.update}"
process="#{cc.clientId}"
oncomplete="postprocess('#{cc.widgetVar}_tree')"
listener="#{cc.onChangeSelection()}"/>
<p:ajax event="unselect"
update="#{cc.clientId}:selected-values #{cc.clientId}:tree #{cc.attrs.update}"
process="#{cc.clientId}"
oncomplete="postprocess('#{cc.widgetVar}_tree')"
listener="#{cc.onChangeSelection()}"/>
<p:ajax event="expand"
oncomplete="postprocess('#{cc.widgetVar}_tree')"/>
<p:treeNode styleClass="#{node.readOnly ? 'ui-state-disabled' : '' }">
<h:outputText value="#{node.name}"/>
</p:treeNode>
</p:tree>
</p:overlayPanel>
</div>
</cc:implementation>
</code>
<code> <cc:interface componentType="selectManyTreeList"> <cc:attribute name="value" type="java.util.Collection" required="true" shortDescription="Collection of selected NodeDTO's values. Must not be null!"/> <cc:attribute name="items" type="java.util.List" required="true" shortDescription="List items, should contains NodeDTO"/> <cc:attribute name="disabled" type="boolean" required="false" default="false"/> <!--TODO: сделать через cc:clientBehavior--> <cc:attribute name="update" type="java.lang.String" required="false" shortDescription="Component(s) id to update"/> <cc:attribute name="styleClass" type="java.lang.String" required="false" shortDescription="Style class of the component"/> <cc:attribute name="propagateSelectionUp" type="java.lang.Boolean" required="false" default="true" shortDescription="Select children of selected node"/> <cc:attribute name="propagateSelectionDown" type="java.lang.Boolean" required="false" default="true" shortDescription="Select parent if all children selected"/> <cc:attribute name="highlightBranchChips" type="java.lang.Boolean" required="false" default="false" shortDescription="Highlight chips for nodes, that have child nodes"/> <cc:attribute name="onChangeSelection" method-signature="void listener(java.util.Collection)" required="false" shortDescription="An application select/unselect listener"/> </cc:interface> <cc:implementation> <div id="#{cc.clientId}" class="#{cc.attrs.styleClass} select-tree-list #{cc.attrs.disabled ? 'ui-state-disabled':''}"> <div class="p-px-2 selected-values-area"> <div jsf:id="selected-values" class="p-col p-p-2 select-tree-list-chips"> <ui:repeat value="#{cc.selections}" var="node"> <!--@elvariable id="node" type="com.spring.jsf.spring_jsf.dto.NodeDTO"--> <p:chip label="#{node.data.name}" styleClass="#{cc.attrs.highlightBranchChips and node.data.hasChildren ? 'branchChip' : ''}" removable="#{not cc.attrs.disabled}" removeIcon="pi pi-times"> <p:ajax event="close" listener="#{cc.onRemoveNode(node)}"/> </p:chip> </ui:repeat> </div> <div jsf:id="clickable-area" class="clickable-area"></div> <div class="p-p-2 chevron"> <i class="pi pi-chevron-down"/> </div> </div> <p:overlayPanel for="clickable-area" styleClass="select-tree-list-overlay" appendTo="@form"> <!--@elvariable id="node" type="com.spring.jsf.spring_jsf.dto.NodeDTO"--> <p:tree var="node" id="tree" widgetVar="#{cc.widgetVar}_tree" binding="#{cc.tree}" value="#{cc.rootNode}" filterBy="#{node.name}" filterMatchMode="contains" selectionMode="checkbox" propagateSelectionUp="#{cc.attrs.propagateSelectionUp}" propagateSelectionDown="#{cc.attrs.propagateSelectionDown}"> <p:ajax event="select" update="#{cc.clientId}:selected-values #{cc.clientId}:tree #{cc.attrs.update}" process="#{cc.clientId}" oncomplete="postprocess('#{cc.widgetVar}_tree')" listener="#{cc.onChangeSelection()}"/> <p:ajax event="unselect" update="#{cc.clientId}:selected-values #{cc.clientId}:tree #{cc.attrs.update}" process="#{cc.clientId}" oncomplete="postprocess('#{cc.widgetVar}_tree')" listener="#{cc.onChangeSelection()}"/> <p:ajax event="expand" oncomplete="postprocess('#{cc.widgetVar}_tree')"/> <p:treeNode styleClass="#{node.readOnly ? 'ui-state-disabled' : '' }"> <h:outputText value="#{node.name}"/> </p:treeNode> </p:tree> </p:overlayPanel> </div> </cc:implementation> </code>

    <cc:interface componentType="selectManyTreeList">
        <cc:attribute name="value" type="java.util.Collection" required="true"
                      shortDescription="Collection of selected NodeDTO's values. Must not be null!"/>
        <cc:attribute name="items" type="java.util.List" required="true"
                      shortDescription="List items, should contains NodeDTO"/>
        <cc:attribute name="disabled" type="boolean" required="false"
                      default="false"/>
        <!--TODO: сделать через cc:clientBehavior-->
        <cc:attribute name="update" type="java.lang.String" required="false"
                      shortDescription="Component(s) id to update"/>
        <cc:attribute name="styleClass" type="java.lang.String" required="false"
                      shortDescription="Style class of the component"/>
        <cc:attribute name="propagateSelectionUp" type="java.lang.Boolean" required="false"
                      default="true" shortDescription="Select children of selected node"/>
        <cc:attribute name="propagateSelectionDown" type="java.lang.Boolean" required="false"
                      default="true" shortDescription="Select parent if all children selected"/>
        <cc:attribute name="highlightBranchChips" type="java.lang.Boolean" required="false"
                      default="false" shortDescription="Highlight chips for nodes, that have child nodes"/>
        <cc:attribute name="onChangeSelection" method-signature="void listener(java.util.Collection)"  required="false"
                      shortDescription="An application select/unselect listener"/>
    </cc:interface>

    <cc:implementation>
        <div id="#{cc.clientId}"
             class="#{cc.attrs.styleClass} select-tree-list #{cc.attrs.disabled ? 'ui-state-disabled':''}">
            <div class="p-px-2 selected-values-area">
                <div jsf:id="selected-values"
                     class="p-col p-p-2 select-tree-list-chips">
                    <ui:repeat value="#{cc.selections}" var="node">
                        <!--@elvariable id="node" type="com.spring.jsf.spring_jsf.dto.NodeDTO"-->
                        <p:chip label="#{node.data.name}"
                                styleClass="#{cc.attrs.highlightBranchChips and node.data.hasChildren ? 'branchChip' : ''}"
                                removable="#{not cc.attrs.disabled}"
                                removeIcon="pi pi-times">
                            <p:ajax event="close"
                                    listener="#{cc.onRemoveNode(node)}"/>
                        </p:chip>
                    </ui:repeat>
                </div>
                <div jsf:id="clickable-area" class="clickable-area"></div>
                <div class="p-p-2 chevron">
                    <i class="pi pi-chevron-down"/>
                </div>
            </div>
            <p:overlayPanel
                    for="clickable-area"
                    styleClass="select-tree-list-overlay"
                    appendTo="@form">
                <!--@elvariable id="node" type="com.spring.jsf.spring_jsf.dto.NodeDTO"-->
                <p:tree var="node"
                        id="tree"
                        widgetVar="#{cc.widgetVar}_tree"
                        binding="#{cc.tree}"
                        value="#{cc.rootNode}"
                        filterBy="#{node.name}"
                        filterMatchMode="contains"
                        selectionMode="checkbox"
                        propagateSelectionUp="#{cc.attrs.propagateSelectionUp}"
                        propagateSelectionDown="#{cc.attrs.propagateSelectionDown}">
                    <p:ajax event="select"
                            update="#{cc.clientId}:selected-values #{cc.clientId}:tree #{cc.attrs.update}"
                            process="#{cc.clientId}"
                            oncomplete="postprocess('#{cc.widgetVar}_tree')"
                            listener="#{cc.onChangeSelection()}"/>
                    <p:ajax event="unselect"
                            update="#{cc.clientId}:selected-values #{cc.clientId}:tree #{cc.attrs.update}"
                            process="#{cc.clientId}"
                            oncomplete="postprocess('#{cc.widgetVar}_tree')"
                            listener="#{cc.onChangeSelection()}"/>
                    <p:ajax event="expand"
                            oncomplete="postprocess('#{cc.widgetVar}_tree')"/>
                    <p:treeNode styleClass="#{node.readOnly ? 'ui-state-disabled' : '' }">
                        <h:outputText value="#{node.name}"/>
                    </p:treeNode>
                </p:tree>
            </p:overlayPanel>
        </div>
    </cc:implementation>

Class SelectManyTreeList:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>@FacesComponent("selectManyTreeList")
@ResourceDependencies({
@ResourceDependency(name = "css/select-tree-list.css", library = "components"),
@ResourceDependency(name = "js/selectManyTreeList.js", library = "components"),
@ResourceDependency(
library = ResourceHandler.JSF_SCRIPT_LIBRARY_NAME,
name = ResourceHandler.JSF_SCRIPT_RESOURCE_NAME,
target = "head")
})
public class SelectManyTreeList extends UIInput implements NamingContainer {
private Tree tree;
enum PropertyKeys {
rootNode,
items,
disabled,
update,
onChangeSelection,
propagateSelectionUp,
propagateSelectionDown,
highlightBranchChips
}
@Override
public String getFamily() {
return UINamingContainer.COMPONENT_FAMILY;
}
@Override
public void processUpdates(FacesContext context) {
processTree();
super.processUpdates(context);
}
@Override
public void encodeBegin(FacesContext context) throws IOException {
processTree();
super.encodeBegin(context);
}
@Override
public void encodeEnd(FacesContext context) throws IOException {
super.encodeEnd(context);
this.saveState(getFacesContext());
tree.saveState(getFacesContext());
}
private void processTree() {
Objects.requireNonNull(getValue(), "Value of selectManyTreeList must not be null!");
TreeNode rootNode = new CheckboxTreeNode();
List<TreeNode> nodes = NodeUtils.createTreeNodes(rootNode, getItems(), CheckboxTreeNode::new);
List<TreeNode> selectedNodes = ((Collection<?>) getValue()).stream()
.map(v -> NodeUtils.findNode(v, nodes).orElse(null))
.filter(Objects::nonNull)
.collect(Collectors.toList());
selectedNodes.forEach(node -> {
node.setSelected(true);
NodeUtils.expandParents(node);
});
tree.setSelection(selectedNodes.toArray(new TreeNode[0]));
setRootNode(rootNode);
}
@Override
public Object getValue() {
Object value = isLocalValueSet() ? getLocalValue() : super.getValue();
if (value == null) {
return Collections.emptyList();
}
return value;
}
@Override
public Object getSubmittedValue() {
if (getSelections() == null) {
return null;
}
return Stream.of(getSelections())
.map(node -> NodeUtils.getNodeValue(node).orElse(null))
.filter(Objects::nonNull)
.collect(Collectors.toCollection(this::createValueCollection));
}
@SuppressWarnings("unchecked")
private Collection<Object> createValueCollection() {
try {
return (Collection<Object>) getValue().getClass().newInstance();
} catch (InstantiationException | IllegalAccessException e) {
throw new RuntimeException(e);
}
}
public TreeNode[] getSelections() {
return (TreeNode[]) tree.getSelection();
}
@SuppressWarnings("unchecked")
private Collection<NodeDTO> getItems() {
return (Collection<NodeDTO>) getStateHelper()
.eval(PropertyKeys.items, Collections.EMPTY_LIST);
}
public void onChangeSelection() {
CompositeUtils.invokeMethod(PropertyKeys.onChangeSelection, getAttributes(), getSubmittedValue());
}
public Tree getTree() {
return tree;
}
public void setTree(Tree tree) {
this.tree = tree;
}
public TreeNode getRootNode() {
return (TreeNode) getStateHelper().eval(PropertyKeys.rootNode);
}
public void setRootNode(TreeNode rootNode) {
getStateHelper().put(PropertyKeys.rootNode, rootNode);
}
public void onRemoveNode(TreeNode treeNode) {
String rowKey = treeNode.getRowKey();
String treeWV = getWidgetVar() + "_tree";
String elementId = getClientId() + ":tree:" + rowKey;
String script = String.format("PF('%s').toggleCheckboxNode($("[id='%s']"))", treeWV, elementId);
PrimeFaces.current().executeScript(script);
}
public String getWidgetVar() {
//Default name для widgetVar в Primefaces
return "widget_" + getClientId().replace(":", "_");
}
}
</code>
<code>@FacesComponent("selectManyTreeList") @ResourceDependencies({ @ResourceDependency(name = "css/select-tree-list.css", library = "components"), @ResourceDependency(name = "js/selectManyTreeList.js", library = "components"), @ResourceDependency( library = ResourceHandler.JSF_SCRIPT_LIBRARY_NAME, name = ResourceHandler.JSF_SCRIPT_RESOURCE_NAME, target = "head") }) public class SelectManyTreeList extends UIInput implements NamingContainer { private Tree tree; enum PropertyKeys { rootNode, items, disabled, update, onChangeSelection, propagateSelectionUp, propagateSelectionDown, highlightBranchChips } @Override public String getFamily() { return UINamingContainer.COMPONENT_FAMILY; } @Override public void processUpdates(FacesContext context) { processTree(); super.processUpdates(context); } @Override public void encodeBegin(FacesContext context) throws IOException { processTree(); super.encodeBegin(context); } @Override public void encodeEnd(FacesContext context) throws IOException { super.encodeEnd(context); this.saveState(getFacesContext()); tree.saveState(getFacesContext()); } private void processTree() { Objects.requireNonNull(getValue(), "Value of selectManyTreeList must not be null!"); TreeNode rootNode = new CheckboxTreeNode(); List<TreeNode> nodes = NodeUtils.createTreeNodes(rootNode, getItems(), CheckboxTreeNode::new); List<TreeNode> selectedNodes = ((Collection<?>) getValue()).stream() .map(v -> NodeUtils.findNode(v, nodes).orElse(null)) .filter(Objects::nonNull) .collect(Collectors.toList()); selectedNodes.forEach(node -> { node.setSelected(true); NodeUtils.expandParents(node); }); tree.setSelection(selectedNodes.toArray(new TreeNode[0])); setRootNode(rootNode); } @Override public Object getValue() { Object value = isLocalValueSet() ? getLocalValue() : super.getValue(); if (value == null) { return Collections.emptyList(); } return value; } @Override public Object getSubmittedValue() { if (getSelections() == null) { return null; } return Stream.of(getSelections()) .map(node -> NodeUtils.getNodeValue(node).orElse(null)) .filter(Objects::nonNull) .collect(Collectors.toCollection(this::createValueCollection)); } @SuppressWarnings("unchecked") private Collection<Object> createValueCollection() { try { return (Collection<Object>) getValue().getClass().newInstance(); } catch (InstantiationException | IllegalAccessException e) { throw new RuntimeException(e); } } public TreeNode[] getSelections() { return (TreeNode[]) tree.getSelection(); } @SuppressWarnings("unchecked") private Collection<NodeDTO> getItems() { return (Collection<NodeDTO>) getStateHelper() .eval(PropertyKeys.items, Collections.EMPTY_LIST); } public void onChangeSelection() { CompositeUtils.invokeMethod(PropertyKeys.onChangeSelection, getAttributes(), getSubmittedValue()); } public Tree getTree() { return tree; } public void setTree(Tree tree) { this.tree = tree; } public TreeNode getRootNode() { return (TreeNode) getStateHelper().eval(PropertyKeys.rootNode); } public void setRootNode(TreeNode rootNode) { getStateHelper().put(PropertyKeys.rootNode, rootNode); } public void onRemoveNode(TreeNode treeNode) { String rowKey = treeNode.getRowKey(); String treeWV = getWidgetVar() + "_tree"; String elementId = getClientId() + ":tree:" + rowKey; String script = String.format("PF('%s').toggleCheckboxNode($("[id='%s']"))", treeWV, elementId); PrimeFaces.current().executeScript(script); } public String getWidgetVar() { //Default name для widgetVar в Primefaces return "widget_" + getClientId().replace(":", "_"); } } </code>
@FacesComponent("selectManyTreeList")
@ResourceDependencies({
        @ResourceDependency(name = "css/select-tree-list.css", library = "components"),
        @ResourceDependency(name = "js/selectManyTreeList.js", library = "components"),
        @ResourceDependency(
                library = ResourceHandler.JSF_SCRIPT_LIBRARY_NAME,
                name = ResourceHandler.JSF_SCRIPT_RESOURCE_NAME,
                target = "head")
})
public class SelectManyTreeList extends UIInput implements NamingContainer {

    private Tree tree;

    enum PropertyKeys {
        rootNode,
        items,
        disabled,
        update,
        onChangeSelection,
        propagateSelectionUp,
        propagateSelectionDown,
        highlightBranchChips
    }

    @Override
    public String getFamily() {
        return UINamingContainer.COMPONENT_FAMILY;
    }

    @Override
    public void processUpdates(FacesContext context) {
        processTree();
        super.processUpdates(context);
    }

    @Override
    public void encodeBegin(FacesContext context) throws IOException {
        processTree();
        super.encodeBegin(context);
    }

    @Override
    public void encodeEnd(FacesContext context) throws IOException {
        super.encodeEnd(context);
        this.saveState(getFacesContext());
        tree.saveState(getFacesContext());
    }

    private void processTree() {
        Objects.requireNonNull(getValue(), "Value of selectManyTreeList must not be null!");
        TreeNode rootNode = new CheckboxTreeNode();
        List<TreeNode> nodes = NodeUtils.createTreeNodes(rootNode, getItems(), CheckboxTreeNode::new);
        List<TreeNode> selectedNodes = ((Collection<?>) getValue()).stream()
                .map(v -> NodeUtils.findNode(v, nodes).orElse(null))
                .filter(Objects::nonNull)
                .collect(Collectors.toList());
        selectedNodes.forEach(node -> {
            node.setSelected(true);
            NodeUtils.expandParents(node);
        });
        tree.setSelection(selectedNodes.toArray(new TreeNode[0]));
        setRootNode(rootNode);
    }

    @Override
    public Object getValue() {
        Object value = isLocalValueSet() ? getLocalValue() : super.getValue();
        if (value == null) {
            return Collections.emptyList();
        }
        return value;
    }

    @Override
    public Object getSubmittedValue() {
        if (getSelections() == null) {
            return null;
        }
        return Stream.of(getSelections())
                .map(node -> NodeUtils.getNodeValue(node).orElse(null))
                .filter(Objects::nonNull)
                .collect(Collectors.toCollection(this::createValueCollection));
    }

    @SuppressWarnings("unchecked")
    private Collection<Object> createValueCollection() {
        try {
            return (Collection<Object>) getValue().getClass().newInstance();
        } catch (InstantiationException | IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }

    public TreeNode[] getSelections() {
        return (TreeNode[]) tree.getSelection();
    }

    @SuppressWarnings("unchecked")
    private Collection<NodeDTO> getItems() {
        return (Collection<NodeDTO>) getStateHelper()
                .eval(PropertyKeys.items, Collections.EMPTY_LIST);
    }

    public void onChangeSelection() {
        CompositeUtils.invokeMethod(PropertyKeys.onChangeSelection, getAttributes(), getSubmittedValue());
    }

    public Tree getTree() {
        return tree;
    }

    public void setTree(Tree tree) {
        this.tree = tree;
    }

    public TreeNode getRootNode() {
        return (TreeNode) getStateHelper().eval(PropertyKeys.rootNode);
    }

    public void setRootNode(TreeNode rootNode) {
        getStateHelper().put(PropertyKeys.rootNode, rootNode);
    }

    public void onRemoveNode(TreeNode treeNode) {
        String rowKey = treeNode.getRowKey();
        String treeWV = getWidgetVar() + "_tree";
        String elementId = getClientId() + ":tree:" + rowKey;
        String script = String.format("PF('%s').toggleCheckboxNode($("[id='%s']"))", treeWV, elementId);
        PrimeFaces.current().executeScript(script);
    }

    public String getWidgetVar() {
        //Default name для widgetVar в Primefaces
        return "widget_" + getClientId().replace(":", "_");
    }

}

index.xhtml:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code><!DOCTYPE html>
<html>
<h:head>
<f:metadata>
<f:event type="preRenderView"
listener="#{bean.onRenderView()}" />
</f:metadata>
</h:head>
<f:view>
<h:body>
<h:form id="example">
<h3>STATIC</h3>
<custom:selectOneTreeList id="selectOneTreeList" items="#{bean.getNodes()}" value="#{bean.selectedValue}" />
<custom:selectManyTreeList id="selectManyTreeList" items="#{bean.getNodes()}" value="#{bean.selectedValues}"
propagateSelectionDown="false" propagateSelectionUp="false"
highlightBranchChips="true" />
<h3>DYNAMIC</h3>
</h:form>
</h:body>
</f:view>
</html>
</code>
<code><!DOCTYPE html> <html> <h:head> <f:metadata> <f:event type="preRenderView" listener="#{bean.onRenderView()}" /> </f:metadata> </h:head> <f:view> <h:body> <h:form id="example"> <h3>STATIC</h3> <custom:selectOneTreeList id="selectOneTreeList" items="#{bean.getNodes()}" value="#{bean.selectedValue}" /> <custom:selectManyTreeList id="selectManyTreeList" items="#{bean.getNodes()}" value="#{bean.selectedValues}" propagateSelectionDown="false" propagateSelectionUp="false" highlightBranchChips="true" /> <h3>DYNAMIC</h3> </h:form> </h:body> </f:view> </html> </code>
<!DOCTYPE html>
<html>
<h:head>
    <f:metadata>
        <f:event type="preRenderView"
                 listener="#{bean.onRenderView()}" />
    </f:metadata>
</h:head>

<f:view>
    <h:body>
        <h:form id="example">
            <h3>STATIC</h3>
            <custom:selectOneTreeList id="selectOneTreeList" items="#{bean.getNodes()}" value="#{bean.selectedValue}" />
            <custom:selectManyTreeList id="selectManyTreeList" items="#{bean.getNodes()}" value="#{bean.selectedValues}"
                                       propagateSelectionDown="false" propagateSelectionUp="false"
                                       highlightBranchChips="true" />
            <h3>DYNAMIC</h3>
        </h:form>
    </h:body>
</f:view>
</html>

Class Bean:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>@Model
public class Bean implements Serializable {
private final List<NodeDTO> nodes;
private Map<String, Object> selectedValue;
private List<Map<String, Object>> selectedValues = new ArrayList<>();
public Bean() {
final Map<String, Object> one = Collections.singletonMap("One", 1);
final Map<String, Object> two = Collections.singletonMap("Two", 2);
final Map<String, Object> three = Collections.singletonMap("Three", 3);
final NodeDTO parent = new NodeDTO("One", one, null, true);
final NodeDTO nodeChild1 = new NodeDTO("Two", two, one, true);
final NodeDTO nodeChild2 = new NodeDTO("Three", three, two, false);
this.nodes = Arrays.asList(parent, nodeChild1, nodeChild2);
}
public void onRenderView() {
if (isRequestMethodGet()) {
final UIComponent root = FacesContext.getCurrentInstance().getViewRoot();
final UIComponent body = root.getChildren().stream().filter(c -> c instanceof HtmlBody).findFirst()
.orElseThrow(IllegalArgumentException::new);
final UIComponent form = body.getChildren().get(0);
//selectOneTreeList dynamic adding
final UIComponent selectOneTreeList = includeCompositeComponent(form, "components",
"selectOneTreeList.xhtml", "selectOneTreeListDynamic");
selectOneTreeList.setValueExpression("value", ELUtils.createValueExpression("#{bean.selectedValue}"));
selectOneTreeList.setValueExpression("items", ELUtils.createValueExpression("#{bean.getNodes()}"));
//selectManyTreeList dynamic adding
final UIComponent selectManyTreeList = includeCompositeComponent(form, "components",
"selectManyTreeList.xhtml",
"selectManyTreeListDynamic");
selectManyTreeList.setValueExpression("value", ELUtils.createValueExpression("#{bean.selectedValues}"));
selectManyTreeList.setValueExpression("items", ELUtils.createValueExpression("#{bean.getNodes()}"));
selectManyTreeList.setValueExpression("propagateSelectionDown", ELUtils.createValueExpression("#{false}"));
selectManyTreeList.setValueExpression("propagateSelectionUp", ELUtils.createValueExpression("#{false}"));
selectManyTreeList.setValueExpression("highlightBranchChips", ELUtils.createValueExpression("#{true}"));
}
}
public List<NodeDTO> getNodes() {
return nodes;
}
public static boolean isRequestMethodGet() {
return Objects
.equals(((HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext()
.getRequest()).getMethod(), RequestMethod.GET.name());
}
public static String getExpression(String param) {
return "#{" + param + "}";
}
public Map<String, Object> getSelectedValue() {
return selectedValue;
}
public void setSelectedValue(Map<String, Object> selectedValue) {
this.selectedValue = selectedValue;
}
public List<Map<String, Object>> getSelectedValues() {
return selectedValues;
}
public void setSelectedValues(List<Map<String, Object>> selectedValues) {
this.selectedValues = selectedValues;
}
</code>
<code>@Model public class Bean implements Serializable { private final List<NodeDTO> nodes; private Map<String, Object> selectedValue; private List<Map<String, Object>> selectedValues = new ArrayList<>(); public Bean() { final Map<String, Object> one = Collections.singletonMap("One", 1); final Map<String, Object> two = Collections.singletonMap("Two", 2); final Map<String, Object> three = Collections.singletonMap("Three", 3); final NodeDTO parent = new NodeDTO("One", one, null, true); final NodeDTO nodeChild1 = new NodeDTO("Two", two, one, true); final NodeDTO nodeChild2 = new NodeDTO("Three", three, two, false); this.nodes = Arrays.asList(parent, nodeChild1, nodeChild2); } public void onRenderView() { if (isRequestMethodGet()) { final UIComponent root = FacesContext.getCurrentInstance().getViewRoot(); final UIComponent body = root.getChildren().stream().filter(c -> c instanceof HtmlBody).findFirst() .orElseThrow(IllegalArgumentException::new); final UIComponent form = body.getChildren().get(0); //selectOneTreeList dynamic adding final UIComponent selectOneTreeList = includeCompositeComponent(form, "components", "selectOneTreeList.xhtml", "selectOneTreeListDynamic"); selectOneTreeList.setValueExpression("value", ELUtils.createValueExpression("#{bean.selectedValue}")); selectOneTreeList.setValueExpression("items", ELUtils.createValueExpression("#{bean.getNodes()}")); //selectManyTreeList dynamic adding final UIComponent selectManyTreeList = includeCompositeComponent(form, "components", "selectManyTreeList.xhtml", "selectManyTreeListDynamic"); selectManyTreeList.setValueExpression("value", ELUtils.createValueExpression("#{bean.selectedValues}")); selectManyTreeList.setValueExpression("items", ELUtils.createValueExpression("#{bean.getNodes()}")); selectManyTreeList.setValueExpression("propagateSelectionDown", ELUtils.createValueExpression("#{false}")); selectManyTreeList.setValueExpression("propagateSelectionUp", ELUtils.createValueExpression("#{false}")); selectManyTreeList.setValueExpression("highlightBranchChips", ELUtils.createValueExpression("#{true}")); } } public List<NodeDTO> getNodes() { return nodes; } public static boolean isRequestMethodGet() { return Objects .equals(((HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext() .getRequest()).getMethod(), RequestMethod.GET.name()); } public static String getExpression(String param) { return "#{" + param + "}"; } public Map<String, Object> getSelectedValue() { return selectedValue; } public void setSelectedValue(Map<String, Object> selectedValue) { this.selectedValue = selectedValue; } public List<Map<String, Object>> getSelectedValues() { return selectedValues; } public void setSelectedValues(List<Map<String, Object>> selectedValues) { this.selectedValues = selectedValues; } </code>
@Model
public class Bean implements Serializable {

    private final List<NodeDTO> nodes;

    private Map<String, Object> selectedValue;

    private List<Map<String, Object>> selectedValues = new ArrayList<>();

    public Bean() {
        final Map<String, Object> one = Collections.singletonMap("One", 1);
        final Map<String, Object> two = Collections.singletonMap("Two", 2);
        final Map<String, Object> three = Collections.singletonMap("Three", 3);
        final NodeDTO parent = new NodeDTO("One", one, null, true);
        final NodeDTO nodeChild1 = new NodeDTO("Two", two, one, true);
        final NodeDTO nodeChild2 = new NodeDTO("Three", three, two, false);
        this.nodes = Arrays.asList(parent, nodeChild1, nodeChild2);
    }

    public void onRenderView() {
        if (isRequestMethodGet()) {
            final UIComponent root = FacesContext.getCurrentInstance().getViewRoot();
            final UIComponent body = root.getChildren().stream().filter(c -> c instanceof HtmlBody).findFirst()
                    .orElseThrow(IllegalArgumentException::new);
            final UIComponent form = body.getChildren().get(0);

            //selectOneTreeList dynamic adding
            final UIComponent selectOneTreeList = includeCompositeComponent(form, "components",
                    "selectOneTreeList.xhtml", "selectOneTreeListDynamic");
            selectOneTreeList.setValueExpression("value", ELUtils.createValueExpression("#{bean.selectedValue}"));
            selectOneTreeList.setValueExpression("items", ELUtils.createValueExpression("#{bean.getNodes()}"));

            //selectManyTreeList dynamic adding
            final UIComponent selectManyTreeList = includeCompositeComponent(form, "components",
                    "selectManyTreeList.xhtml",
                    "selectManyTreeListDynamic");
            selectManyTreeList.setValueExpression("value", ELUtils.createValueExpression("#{bean.selectedValues}"));
            selectManyTreeList.setValueExpression("items", ELUtils.createValueExpression("#{bean.getNodes()}"));
            selectManyTreeList.setValueExpression("propagateSelectionDown", ELUtils.createValueExpression("#{false}"));
            selectManyTreeList.setValueExpression("propagateSelectionUp", ELUtils.createValueExpression("#{false}"));
            selectManyTreeList.setValueExpression("highlightBranchChips", ELUtils.createValueExpression("#{true}"));
        }
    }

    public List<NodeDTO> getNodes() {
        return nodes;
    }

    public static boolean isRequestMethodGet() {
        return Objects
                .equals(((HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext()
                        .getRequest()).getMethod(), RequestMethod.GET.name());
    }

    public static String getExpression(String param) {
        return "#{" + param + "}";
    }

    public Map<String, Object> getSelectedValue() {
        return selectedValue;
    }

    public void setSelectedValue(Map<String, Object> selectedValue) {
        this.selectedValue = selectedValue;
    }

    public List<Map<String, Object>> getSelectedValues() {
        return selectedValues;
    }

    public void setSelectedValues(List<Map<String, Object>> selectedValues) {
        this.selectedValues = selectedValues;
    }

How I’m trying to add component:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>public static UIComponent includeCompositeComponent(UIComponent parent, String libraryName, String resourceName,
String id) {
FacesContext context = FacesContext.getCurrentInstance();
Application application = context.getApplication();
FaceletContext faceletContext = (FaceletContext) context.getAttributes()
.get(FaceletContext.FACELET_CONTEXT_KEY);
Resource resource = application.getResourceHandler().createResource(resourceName, libraryName);
UIComponent composite = application.createComponent(context, resource);
composite.setId(id);
UIComponent implementation = application.createComponent(UIPanel.COMPONENT_TYPE);
implementation.setRendererType("javax.faces.Group");
composite.getFacets().put(UIComponent.COMPOSITE_FACET_NAME, implementation);
if (parent != null) {
composite.pushComponentToEL(context, implementation);
parent.pushComponentToEL(context, composite);
}
try {
faceletContext.includeFacelet(implementation, resource.getURL());
} catch (IOException e) {
throw new FacesException(e);
} finally {
if (parent != null) {
parent.getChildren().add(composite);
}
}
return composite;
}
</code>
<code>public static UIComponent includeCompositeComponent(UIComponent parent, String libraryName, String resourceName, String id) { FacesContext context = FacesContext.getCurrentInstance(); Application application = context.getApplication(); FaceletContext faceletContext = (FaceletContext) context.getAttributes() .get(FaceletContext.FACELET_CONTEXT_KEY); Resource resource = application.getResourceHandler().createResource(resourceName, libraryName); UIComponent composite = application.createComponent(context, resource); composite.setId(id); UIComponent implementation = application.createComponent(UIPanel.COMPONENT_TYPE); implementation.setRendererType("javax.faces.Group"); composite.getFacets().put(UIComponent.COMPOSITE_FACET_NAME, implementation); if (parent != null) { composite.pushComponentToEL(context, implementation); parent.pushComponentToEL(context, composite); } try { faceletContext.includeFacelet(implementation, resource.getURL()); } catch (IOException e) { throw new FacesException(e); } finally { if (parent != null) { parent.getChildren().add(composite); } } return composite; } </code>
public static UIComponent includeCompositeComponent(UIComponent parent, String libraryName, String resourceName,
            String id) {
        FacesContext context = FacesContext.getCurrentInstance();
        Application application = context.getApplication();
        FaceletContext faceletContext = (FaceletContext) context.getAttributes()
                .get(FaceletContext.FACELET_CONTEXT_KEY);

        Resource resource = application.getResourceHandler().createResource(resourceName, libraryName);
        UIComponent composite = application.createComponent(context, resource);

        composite.setId(id);

        UIComponent implementation = application.createComponent(UIPanel.COMPONENT_TYPE);
        implementation.setRendererType("javax.faces.Group");

        composite.getFacets().put(UIComponent.COMPOSITE_FACET_NAME, implementation);

        if (parent != null) {
            composite.pushComponentToEL(context, implementation);
            parent.pushComponentToEL(context, composite);
        }
        try {
            faceletContext.includeFacelet(implementation, resource.getURL());
        } catch (IOException e) {
            throw new FacesException(e);
        } finally {
            if (parent != null) {
                parent.getChildren().add(composite);
            }
        }
        return composite;
    }

I kindly ask for help with the problem or advice on how to solve it.

New contributor

Kirill Savitsky is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật