PrimeFaces markup remains after navigation in Liferay 7.0 - jsf

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?

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:
https://issues.liferay.com/browse/FACES-2677
https://web.liferay.com/community/forums/-/message_boards/view_message/105009688
https://web.liferay.com/community/forums/-/message_boards/view_message/94179972

Related

Should I use ui:fragment with the render attribute to conditionally render HTML tags in Facelets with JSF 2.2?

I am in the process of upgrading an old project from JSF 1.1 to JSF 2.2. Specifically, I am upgrading the JSF implementation from MyFaces 1.1 to MyFaces 2.2.12, replacing JSPs with Facelets and upgrading/replacing outdated tag libraries. I am mainly using Migrating from JSF 1.2 to JSF 2.0 as a guide.
The project used some tag library called htmLib with the namespace http://jsftutorials.net/htmLib in it's JSP pages. I can't find any documentation about this tag library anymore, neither on the jsftutorials webpage nor elsewhere, but apparently it was used to include plain HTML tags like <div> or <table> in JSP pages.
Since plain HTML tags can now be used in XML Facelets with JSF2, I am right now removing all occurences of tags from the htmLib taglib like <htm:div>...</htm:div> and replace them with plain HTML tags like <div>...</div>.
However, some of the tags used from htmLib contain the render attribute for conditional rendering, like this:
<htmLib:h4 render="someCondition">
...
</htmLib:h4>
Because plain HTML tags don't have a render attribute for this purpose, I was searching for an alternative way to conditionally render plain HTML tags and stumbled upon this answer on SO: How to conditionally render plain HTML elements like <div>s?
So, my idea is to replace a construct like the one above with something like
<ui:fragment render="someCondition">
<h4>
...
</h4>
</ui:fragment>
My questions:
Is wrapping HTML tags inside a <ui:fragment> tag with the render
attribute the recommended way to conditionally render HTML tags, or
is this method only valid and recommended for the case in the linked question?
Are there other ways to conditionally render plain HTML tags in Facelets that should be preferred?
Does the <ui:fragment> wrapping method work, no matter what kind of plain HTML is contained within it?
Can conditionally rendered <ui:fragment> blocks be nested?
There's no limitation in that. Not even for wrapping ui:fragment.
Basically:
In order just to control the inner content, with no extra HTML generation use
ui:fragment.
To generate an extra HTML span element, use h:panelGroup.
To generate an extra HTML div element, use h:panelGroup layout="block".
The HTML you have inside isn't a problem. JSF, being a server side framework, performs all the HTML building/rendering job in the server, so the JSF/facelet tags get translated to HTML before the response being sent. All the plain HTML you use inside will remain HTML.
However, beware of using tag handlers inside UI Components when migrating from 1.x. Tag handlers (ui:include, c:if, c:forEach) evaluate before the UI Components (which tipically contain rendered clauses). This has been a source of conflict in JSF 2.

h:body not rerendered when using FullAjaxExceptionHandler

I'm using the OmniFaces FullAjaxExceptionHandler to display error pages. The error pages are shown correctly, but I'm having issues with the styling of those pages.
My application is using a template which has CSS classes defined on the body element. These classes are different for normal and error pages:
Normal page:
<h:body styleClass="main-body layout-compact">
Error page:
<h:body styleClass="exception-body error-page">
When the FullAjaxExceptionHandler processes an exception, a forward to the error page is performed (based on the <error-page> mechanism in web.xml). Apparently this does not rerender the <h:body> tag, because when checking the HTML output, I can see that the <body> tag still contains the CSS classes from the normal page (instead of the classes of the error page).
It seems that the content of the original <h:body> is replaced with the content of the error page <h:body> instead of just replacing the full <h:body>. I don't know if this is default JSF / FullAjaxExceptionHandler behaviour.
Is there any way to have the <h:body> rendered with the correct CSS classes? Moving the CSS classes away from <h:body> is not an option.
This is unfortunately "by design". JSF doesn't replace the entire document when performing ajax navigation, but it only replaces the children of individual <head> and <body> elements, leaving the parents untouched. This is done so for historical reasons; older Internet Explorer versions namely doesn't support replacing them altogether.
What I have done myself is to simply put the style into the <main> element instead. The <header> and <footer> are usually identical anyway in the final HTML output. Basically:
<html>
<head>
<title>...</title>
</head>
<body>
<header>...</header>
<main class="#{page.type}">...</main>
<footer>...</footer>
</body>
</html>
If you really need to have the <body class> modified, then your best bet is to do so via JavaScript embedded in the error page template.
<h:outputScript rendered="#{faces.ajaxRequest}">
document.body.className = "exception-body error-page";
</h:outputScript>
Note: #{faces} is only available since OmniFaces 2.5, if you're using an older version, use instead #{facesContext.partialViewContext.ajaxRequest}).

Load different jsf page on click of a list item

I am new to JSF. I have a unordered list and a div.
<ul class="nav navbar-nav">
<li>Test Page</li>
<li>Item1</li>
<li>Item2</li>
<li>item3</li>
</ul>
<div id="content"></div>
Now on click of the list items I want to load different xhtml pages using JSF. Is it possible to achieve this usecase ? I am using JSF 2.0 and primefaces.
Any help will be really appreciated.
Just replace the plain HTML link by a JSF h:link. According to the docs:
Render an HTML "a" anchor element. The value of the component is rendered as the anchor text and the outcome of the component is used to determine the target URL rendered in the "href" attribute.
<li><h:link outcome="TestPage" value="Test Page" /></li>
Where the outcome attribute specifies the target navigation case.
See also:
Implicit navigation in JSF 2
Note that's useful for using JSF navigation cases. If you want to just perform a GET request for an external non-JSF url, just use the plain HTML way.
On click event of <li> element, you can call $('#content').load(Url, successEventHandler)

How to not render whole block in JSF?

Is there a JSF 2.1 component which lets me conditionally render (or not render) all its content? Something like
<h:component rendered="#{user.loggedIn}">
...a bunch of jsf components and HTML code...
...even more HTML code...
</h:component>
I am using PrimeFaces 3M4 as this may influence your answer!
<h:panelGroup>
If you set attribute layout="block", you will have a <div> tag
Otherwise, you have a <span> tag.
In general most of jsf components support the render attribute (never bumped in some that does not),
container components like h:panelGrid or h:panelGroup supports the rendered attribute and if its set to false all its child will be hidden too
Same goes for the primefaces components ,and if not it probably a bug (i think there was an issue with tabview of primefaces)
Here's a link for primefaces user guide, you can find supported attributes of all primefaces components there User’s Guide for 3.0.M4

How do I have the cursor placed in a dropdown field on page load using jsf?

when I load a page , the cursor must point to drop-down field , using jsf.I am new to JSF.
When the page is finished loading in webbrowser, JSF has already done its job of generating a bunch of HTML on the webserver and sending it to the webbrowser. It can't do any much more for you after that point. You need to use JavaScript for this job. It is able to execute code when the page is finished loading and it has access to all elements in the HTML DOM tree.
So, if you specify a fixed ID for the dropdown element in JSF,
<h:form id="myform">
<h:selectOneMenu id="mydropdown">
...
</h:form>
then you must be able to grab it by JavaScript:
var mydropdown = document.getElementById('myform:mydropdown');
In JavaScript, you can use element.focus() to set the focus on the element:
mydropdown.focus();
To get it to execute then the page is finished loading, you need to hook a function to window.onload:
window.onload = function() {
var mydropdown = document.getElementById('myform:mydropdown');
mydropdown.focus();
}
That's it. Put it in a <script> somewhere near the bottom of the <head> or a .js file which you include by <script src>.
JSF is a server side technology and this type of behavior requires Javascript. Try to write a Javascript to do this in a regular HTML page first. Once you have figured out how to do this you can try to use this script in your JSF page.

Resources