1

I want to add or remove tabs dynamically from an existing ribbon that already contains several tabs. It would be great, if it possible to "include" a tab I already wrote in XHTML or merge two ribbons.

I already tried to add the tabs with

<p:repeat var="tab" value="#{ribbon.tabs}">
    <p:tab binding="#{tab}" />
</p:repeat>

where tabs is a list of Tab.

I also tried to add the list itself into the binding without but the tag cant process a list.

If I add this with the repeat, there is no error, but the tab is not shown. The tabs was generated in java with

public void genTab() {
    Tab t = new Tab();
    t.setTitle("testTab");
    t.setRendered(true);
    t.setParent(FacesContext.getCurrentInstance().getViewRoot().findComponent("menu-ribbon"));
    RibbonGroup r = new RibbonGroup();
    r.setLabel("testgroup");
    r.setRendered(true);
    r.setParent(t);

    addTab(t); //add to list of Tab
}
Hami
  • 11
  • 5

1 Answers1

0

You are correct. Tags like <ui:repeat> and <p:repeat> are invoked during rendering time. There is no guarantee that they will work with all components and it highly depends on how they are designed. The parent component has to have support for dynamic rendering and support these tags - otherwise you are out of luck.

With that said, you can get around this by using JSTL, which will effectively create your ribbon during document build time instead of during rendering time. Using your example as a base this would be implemented like this (Note that this example has dependencies on Lombok and Apache Commons);

<?xml version="1.0" encoding="UTF-8"?>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html"
  xmlns:p="http://primefaces.org/ui" xmlns:c="http://xmlns.jcp.org/jsp/jstl/core">
<h:head>
    <title>Dynamic Ribbon Test</title>
</h:head>
<h:body>
    <h:form>
        <p:ribbon>
            <c:forEach var="tab" items="#{dynRibbonBackingBean.tabs}">
                <p:tab binding="#{tab}" />
            </c:forEach>
        </p:ribbon>
    </h:form>
</h:body>

@Data
@Named
@ViewScoped
public class DynRibbonBackingBean implements Serializable {
    private List<Tab> tabs;

    @PostConstruct
    private void init() {
        tabs = new ArrayList<>();

        for (int i = 0; i < RandomUtils.nextInt(5, 15); i++) {
            final Tab t = new Tab();
            t.setLoaded(true);
            t.setTitle(RandomStringUtils.randomAlphabetic(10));

            final RibbonGroup r = new RibbonGroup();
            r.setLabel(RandomStringUtils.randomAlphabetic(10));
            r.setParent(t);

            tabs.add(t);
        }
    }
}

Here we use the <c:forEach> tag instead to iterate and build the dynamic ribbon during document build time. In this example, I am randomizing the ribbon completely during @PostConstruct, so you can reload the page and watch how the tabs of the ribbon change on each page load (both in count and title).

You can also gain some additional insight into this topic by referring to this previous Q/A here on the site;

When <ui:repeat> works for X but <c:forEach> works for Y

Adam Waldenberg
  • 2,271
  • 9
  • 26