For this tutorial, you’ll learn how to dynamically add portlets to Liferay Portal pages. Here are the places in which you can add a portlet:
- Inside the FreeMarker template or Velocity
template
of a theme with
$theme.runtime()
- Inside a layout template
with
$processor.processPortlet()
- Inside a JSP with
<liferay-portlet:runtime />
Unfortunately, as described in
FACES-244, dynamically adding JSF
portlets doesn’t work very well. It’s actually not limited to JSF portlets–
this problem happens with any portlet that needs to add JS/CSS resources to
the <head>
…</head>
section of the portal page. Since JSF portlets require
the jsf.js
resource to perform Ajax requests, the jsf.js
resource must be
loaded when the portal page is initially rendered.
There are two workarounds:
-
For plain JSF portlets, add a
<link />
element for thejsf.js
resource in the<head>
…</head>
section of theportal_normal.vm
orportal_normal.ftl
file in the theme. The first few lines ofjsf.js
prevent double-instantiation in case it gets included multiple times on a page. This can occur when a JSF portlet is dynamically included and another JSF portlet is added statically. Unfortunately, this approach doesn’t work for PrimeFaces, sinceprimefaces.js
does not prevent double-instantiation. -
Use an IFrame:
<div id="${request.portlet-namespace}my_runtime_portlet"> <script type="text/javascript"> AUI().use('liferay-portlet-url', 'aui-resize-iframe', function(A) { var portletURL = Liferay.PortletURL.createRenderURL(); portletURL.setPortletId('1_WAR_mypluginportlet'); portletURL.setPlid(themeDisplay.getPlid()); var html = '<iframe frameborder="0" id="${request.portlet-namespace}my_runtime_portlet_frame" src="' + portletURL.toString() + '" scrolling="no" width="100%"></iframe>'; A.one('#${request.portlet-namespace}my_runtime_portlet').append(html); A.one('#${request.portlet-namespace}my_runtime_portlet_frame').plug(A.Plugin.ResizeIframe); }); </script> </div>
In order to avoid the You do not have the roles required to access this
portlet error message, add the following directive to the
WEB-INF/liferay-portlet.xml
descriptor:
<add-default-resource>true</add-default-resource>
Alternatively, you can place the portlet alone on a hidden portal page and
then use a portlet URL referring to the plid
of the hidden portal page. This
approach is more appropriate for portlets that perform security-sensitive
actions.
Note, when an end-user dynamically adds any JSF 2 portlet to a portal page, the
JSF 2 standard jsf.js
JavaScript code is not automatically executed. In order
for the jsf.js
to be executed, the page must be fully refreshed.
As a workaround, Liferay Portal provides configuration parameters that allow the
developer to specify that a full page refresh is required. Specifying this
ensures that JSF 2 is properly initialized. You specify the required
<render-weight>
and <ajaxable>
parameter elements in the
WEB-INF/liferay-portlet.xml
configuration file.
<liferay-portlet-app>
<portlet>
<portlet-name>my_portlet</portlet-name>
<instanceable>false</instanceable>
<render-weight>1</render-weight>
<ajaxable>false</ajaxable>
</portlet>
</liferay-portlet-app>
Now, you know the options you have in dynamically adding your JSF portlets at runtime.
Related Topics
Liferay Faces Alloy UI Components
Liferay Faces Bridge UI Components