PrimeFaces markup remains after navigation in Liferay 7.0

275 views Asked by At

I've noticed that when I navigate via GET from a page with certain PrimeFaces components, the markup of these components will appear in the upper left-hand corner of the next page.

This problem has happened with the following components (and probably others):

  • p:tooltip
  • p:columnToggler
  • p:notifiactionBar
  • p:selectOneMenu
  • p:autoComplete
  • p:confirmDialog
  • p:dialog
  • p:draggable
  • p:menuButton
  • p:selectCheckboxMenu
  • p:selectOneMenu
  • p:splitButton

Is there any way I can stop this markup from appearing after navigation?

1

There are 1 answers

0
stiemannkj1 On BEST ANSWER

Update: This issue has been verified as a bug in the Liferay Faces project and has been fixed as part of Bridge Ext 5.0.3: FACES-3328.

Explanation

This problem is due to an incompatibility between PrimeFaces (which was initially designed for webapps) and Liferay 7.0/SennaJS/Portlets. PrimeFaces assumes that it is being used in a webapp environment where it has control over all markup on the page, so many of the components that use JavaScript to help with rendering attach their markup to the <body> tag.

Here's a super simplified version of what PrimeFaces is doing:

<body>
    <script>
        var dynDiv = document.createElement("div");
        var text = document
            .createTextNode("I was created dynamically via JavaScript!"); 
        dynDiv.appendChild(text);
        document.body.appendChild(dynDiv);
    </script>
</body>

However, in a portlet environment, portlet only has control over the portlet markup which is a <div> inside the <body> tag. But since PrimeFaces assumes a webapp environment, it still appends markup to the <body>:

<body>
    <div id="myPrimeFacesPortlet">
        <script>
            var dynDiv = document.createElement("div");
            var text = document
                .createTextNode("I was created dynamically via JavaScript!"); 
            dynDiv.appendChild(text);
            document.body.appendChild(dynDiv);
        </script>
    </div>
</body>

Before Liferay 7.0, this was not a problem though since every navigation would cause a full page load and all the dynamic elements created by PrimeFaces' JavaScript would be destroyed. Now with Liferay 7.0 the Single Page Application engine of SennaJS is used to make sure that only necessary parts of the page are loaded and rendered on navigation. Now when you navigate away from the PrimeFaces portlet via SennaJS all PrimeFaces CSS is removed along with the portlet <div>. The dynamic elements are not removed, and the PrimeFaces CSS is unloaded so it cannot hide them anymore.

Solutions

There are several possible solutions to this problem (I've ordered them from best to worst):

  • If the component has an appendTo attribute, ensure that markup is appended to an element inside the portlet markup: appendTo="@this", appendTo="@id(#{portletNamespace})" (for the outermost <div> of the portlet) or appendTo="@form" should also work (although appendTo="@root" does not appear to work) (see the PF User Guide (p. 558) for more details on the "Search Expression Framework").

  • Permanently hide the dynamic elements with CSS. To ensure the CSS is not removed on SennaJS navigation, set data-senna-track="permanent":

    <h:head>
        <!--You'll need to look at the CSS for each element (not just tooltip)
            to figure out what CSS classes should be hidden. -->
        <style id="hidePrimeFacesLeftoverMarkupWorkaroundCSS"
            data-senna-track="permanent">
            .ui-tooltip {
                display: none;
            }
        </style>
    </h:head>
    
  • Disable SennaJS for your Portlet or your entire Portal.

More Info: