3

I'm using PrimeFaces 3.4 collapsible panels. The problem with actual solution is that panel is toggled via clicking in small button on the right. It is not very ergonomic and the user would expect the toggling via clicking anywhere on header.

This is what I want to implement: trigger the toggle via clicking on header and remove the toggle button. This is what I've written:

$('.ui-panel-titlebar').each(function(){
    var header = $(this);
    var widgetId = 'widget_' + header.attr('id').replace(/:/g, '_').replace(/_header$/, '');
    header.css('cursor', 'pointer');
    var toggler = header.find('a[id$=_toggler]');
    toggler.remove();
    header.click(function(){
        window[widgetId].toggle();
    });
});

But I don't like that solution, because first I'm guessing the JavaScript widget Id, and second, I'm removing the rendered toggle button from DOM tree and I would prefer it not to be rendered at all.

Is there a way to achieve the same effect in more elegant way without writing too many code (so, without rewriting the p:panel)? Using extensions based on same licence as PrimeFaces (commerce-friendly) is acceptable as solution.

Danubian Sailor
  • 1
  • 38
  • 145
  • 223

5 Answers5

5

Since PrimeFaces 6.2, this behavior is supported via the new toggleableHeader-attribute:

<p:panel header="This is my header text"
         toggleable="true"
         toggleableHeader="true">
  The content of the panel.
</p:panel>
Martin Höller
  • 2,714
  • 26
  • 44
2

I had the same problem and was unfortunately not able to find a PrimeFaces solution. I wrote a custom JQuery script which simulate click on the toggle button if the click on the title bar.

$(document).on("click", ".ui-panel:has(.ui-panel-titlebar-icon) .ui-panel-titlebar", function(e) {
    console.log("click:");
    if (e.srcElement != null) { // avoid infinite loop
        $(this).find("a.ui-panel-titlebar-icon").click();
    }
});

Thanks to the on, this works also after any Ajax update. I think that should be easy to set this behaviour only to panels with a given class (e.g. panel-header-click).

I only tested the code on Chrome.

LaurentG
  • 11,128
  • 9
  • 51
  • 66
2

I wanted to have panels that optionally are togglable by clicking on the header, and also to have the icon at the left side of the panel. I chose to create a custom tag to do so.

my.taglib.xml:

<?xml version="1.0" encoding="UTF-8"?>
<facelet-taglib xmlns="http://java.sun.com/xml/ns/javaee"
                xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facelettaglibrary_2_0.xsd"
                version="2.0">
  <namespace>http://my.com/jsf/facelets</namespace>
  <tag>
    <tag-name>togglePanel</tag-name>
    <source>tags/togglePanel.xhtml</source>
    <attribute>
      <name>header</name>
      <required>true</required>
      <type>java.lang.String</type>
    </attribute>
    <attribute>
      <name>collapsed</name>
      <required>false</required>
      <type>boolean</type>
    </attribute>
  </tag>
</facelet-taglib>

togglePanel.xhtml:

<ui:composition xmlns="http://www.w3.org/1999/xhtml"
                xmlns:c="http://java.sun.com/jsp/jstl/core"
                xmlns:f="http://java.sun.com/jsf/core"
                xmlns:h="http://java.sun.com/jsf/html"
                xmlns:ui="http://java.sun.com/jsf/facelets"
                xmlns:p="http://primefaces.org/ui">

  <c:set var="collapsed" value="#{not empty collapsed and collapsed}" />

  <p:panel toggleable="true" collapsed="#{collapsed}" class="myToggleable">
    <f:facet name="header">
      <a href="#" onclick="document.getElementById(this.parentNode.parentNode.id.replace('_header', '_toggler')).click()"><h:outputText
          value="#{header}"/></a>
    </f:facet>
    <ui:insert />
  </p:panel>

</ui:composition>

Style sheet:

.ui-panel.myToggleable .ui-panel-titlebar { 
  position: relative; padding: .5em 1em .3em 2.5em;
}
.ui-panel.myToggleable .ui-panel-title,
.ui-panel.myToggleable .ui-panel-title a {
  display: block; text-decoration: none;
}
.ui-panel.myToggleable .ui-panel-titlebar-icon,
.ui-panel.myToggleable .ui-panel-titlebar-icon:hover {
  position: absolute; left: 10px; top: 10px; margin: 0;
}

Now you can use it like this in your XHTML files:

<my:togglePanel header="Header" collapsed="false">
  ...
</my:togglePanel>

You should add the following namespace though: xmlns:my="http://my.com/jsf/facelets".

This has been tested using PrimeFaces 6.0.

Community
  • 1
  • 1
Jasper de Vries
  • 19,370
  • 6
  • 64
  • 102
1

The p:accordionPanel is a collapsible panel which can be toggled by clicking anywhere on the header.

1

In primefaces 5.2 is

$(document).on("click", ".ui-panel:has(.ui-panel-titlebar-icon) .ui-panel-titlebar", function (e) {
    console.log(e.target.className);
    if (e.target.className === "ui-panel-titlebar ui-widget-header ui-helper-clearfix ui-corner-all"
            || e.target.className === "ui-panel-title"){
        $(this).find("a.ui-panel-titlebar-icon").click();
    }
});
VLS
  • 2,306
  • 4
  • 22
  • 17
GenomaTeam
  • 11
  • 1