JSTL, composite, NamingContainer and prependId - jsf-2

I have written a composite component and want to use the reserved EL #{component.clientId} to make a JQuery bind. To use this retrieved clientId in a another place in the page (outside the component), I use JSTL to store it in a view scope variable. The strange thing is that JSTL seems to prevent the natural composite component behavior of appending its id in front of its children (NamingContainer behavior). I know that JSTL is a little tricky, interfering with other components (ui:repeat for instance) because of lifecycle things, but here I don't understand this behavior.
Some concrete code is better than this long speech:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:rich="http://richfaces.org/rich"
xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:composite="http://java.sun.com/jsf/composite">
<composite:interface>
[…]
</composite:interface>
<composite:implementation>
<rich:dataTable id="mySoLovedDataTable" […]>
#{component.clientId}
<!-- Commenting or uncommenting this line make the whole point -->
<c:set var="targetClientId" value="#{component.clientId}" scope="view" />
[…]
</rich:dataTable>
</composite:implementation>
</html>
With the line commented on, #{component.clientId} gives something like j_idt261:mySoLovedDataTable.
With the line commented out, it gives just mySoLovedDataTable.

JSTL runs during view build time. It runs at the point that JSF parses the view template into a fullworthy and renderable JSF component tree. JSF runs during view render time. It runs at the point that JSF encodes the component tree into a bunch of HTML. You can visualize it as follows: JSTL runs from top to bottom first and produces a result with JSF tags only. Then, during JSF render response phase, JSF will run from top to bottom and produce HTML result.
In other words JSTL and JSF doesn't run in sync as you'd expect from the coding. Usually you would like to use Facelets' <ui:param> instead of JSTL <c:set>.
<ui:param name="targetClientId" value="#{component.clientId}" />
Note that this does not really set anything in any scope. It merely creates kind of an "alias" for the given expression. I'm not sure if it works in your particular case the way as you intend, but as far I understand the functional requirement, you'd like to be able to obtain the client ID <rich:dataTable> further in the view, after the component. In that case, better use binding:
<rich:dataTable binding="#{table}" ...>
...
</rich:dataTable>
<script>
var $table = jQuery("[id='#{table.clientId}']");
// ...
</script>

Related

Primefaces/JSF2 : updating change ui:insert dynamically [duplicate]

I'm just learning JSF 2 thanks to this site I had learned a lot in such a short time.
My question is regarding how to implement a common layout to all my JSF 2 pages and have only the content part of the page refresh not the whole page whenever I click a link/menu from a different panel. I am using the Facelets approach it does what I want except that each time I click a link from a panel (e.g. menu items from left panel) the whole page is refreshed. What I am looking for is a way to refresh only the content part of my page. To illustrate this below is my target pagelayout.
Did not post my code because I'm not sure if Facelets can do this . Are there other approach more suited for my requirement other than Facelets?
A straightforward approach would be the following view:
<h:panelGroup id="header" layout="block">
<h1>Header</h1>
</h:panelGroup>
<h:panelGroup id="menu" layout="block">
<h:form>
<f:ajax render=":content">
<ul>
<li><h:commandLink value="include1" action="#{bean.setPage('include1')}" /></li>
<li><h:commandLink value="include2" action="#{bean.setPage('include2')}" /></li>
<li><h:commandLink value="include3" action="#{bean.setPage('include3')}" /></li>
</ul>
</f:ajax>
</h:form>
</h:panelGroup>
<h:panelGroup id="content" layout="block">
<ui:include src="/WEB-INF/includes/#{bean.page}.xhtml" />
</h:panelGroup>
With this bean:
#ManagedBean
#ViewScoped
public class Bean implements Serializable {
private String page;
#PostConstruct
public void init() {
page = "include1"; // Default include.
}
// +getter+setter.
}
In this example, the actual include templates are include1.xhtml, include2.xhtml and include3.xhtml in /WEB-INF/includes folder (folder and location is fully free to your choice; the files are just placed in /WEB-INF in order to prevent direct access by guessing the URL in browser's address bar).
This approach works in all MyFaces 2.x versions, but requires in case of Mojarra a minimum of 2.3.x. In case you're using a Mojarra version older than 2.3.0, then this all fails when the <ui:include> page in turn contains a <h:form>. Any postback will fail because it is totally missing the view state. You can solve this by upgrading to minimally Mojarra 2.3.0 or with a script found in this answer h:commandButton/h:commandLink does not work on first click, works only on second click. Or, if you're already using PrimeFaces and exclusively use <p:xxx> ajax, then it's already transparently taken into account.
Also, make sure that you're using minimally Mojarra 2.1.18 as older versions will fail in keeping the view scoped bean alive, causing the wrong include being used during postback. If you can't upgrade, then you'd need to fall back to the below (relatively clumsy) approach of conditionally rendering the view instead of conditionally building the view:
...
<h:panelGroup id="content" layout="block">
<ui:fragment rendered="#{bean.page eq 'include1'}">
<ui:include src="include1.xhtml" />
</ui:fragment>
<ui:fragment rendered="#{bean.page eq 'include2'}">
<ui:include src="include2.xhtml" />
</ui:fragment>
<ui:fragment rendered="#{bean.page eq 'include3'}">
<ui:include src="include3.xhtml" />
</ui:fragment>
</h:panelGroup>
The disadvantage is that the view would become relatively large and that all associated managed beans may be unnecessarily initialized even though when they would not be used as per the rendered condition. See also JSTL in JSF2 Facelets... makes sense? for an in depth explanation on <ui:include src="#{...}"> vs <x:someComponent rendered="#{...}">.
As to positioning of the elements, that's just a matter of applying the right CSS. That's beyond the scope of JSF :) At least, <h:panelGroup layout="block"> renders a <div>, so that should be good enough.
Last but not least, this SPA (Single Page Application) approach is not SEO friendly. All the pages are not indexable by searchbots nor bookmarkable by endusers, you may need to fiddle around with HTML5 history in client and provide a server side fallback. Moreover, in case of pages with forms, the very same view scoped bean instance would be reused across all pages, resulting in unintuitive scoping behavior when you navigate back to a previously visited page. I'd suggest to go with templating approach instead as outlined in 2nd part of this answer: How to include another XHTML in XHTML using JSF 2.0 Facelets? See also How to navigate in JSF? How to make URL reflect current page (and not previous one).
If you only want to refresh part of the page, there are only 2 ways to go (for the web in general, not just JSF). You have to use frames or Ajax. JSF 2 supports ajax natively, check out the f:ajax tag to update just 1 component without reloading the entire page.
Netbeans provides a wizard that create the proposed layout with minimal effort using JSF. So, the best way to start is take a look at Facelets Template Wizard and look at the generated source.

Multiple implementations of Facelets composite component interface

I'm working on a JSF 2 application that is composed of a core component that can be extended by (usually client specific) code. Generally speaking: the extended parts of the application precede the core ones.
For the Java code this is done by using conventional mechanisms. For the presentation layer, we use a javax.faces.view.facelets.ResourceResolver implementation that first tries to find resources in the extension jar before the core resources are used.
We use a lot of composite components for reusable markup. Think of components for showing addresses, salaries, etc.
The Facelets are causing major headaches when it comes to the extendable nature of the application and I'm starting to wonder if there is a solution for the problems that we run into.
What we want to achieve, is having a standard interface for composite components, but override the implementation somehow by resolving multiple implementations, out of which the extended implementation should precede the core implementation.
The idea of course is, that the core defines the standard layout/templating of the application, and extensions define client-specific formatting options, or hiding/showing part of the managed model that the application does.
For example:
<ui:composition
xmlns="http://www.w3.org/1999/xhtml"
xmlns:cc="http://java.sun.com/jsf/composite"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:pui="http://java.sun.com/jsf/composite/pui">
<cc:interface>
<cc:attribute name="saveButtonLabel" />
<cc:attribute name="saveButtonIcon" />
<cc:attribute name="saveButtonIconPosition" />
</cc:interface>
<cc:implementation>
<pui:pension_plan_custom_state pensionPlanBean="#{pensionPlanBean}" />
<pui:pension_plan_general pensionPlanBean="#{pensionPlanBean}" />
<pui:pension_plan_pension_plan pensionPlanBean="#{pensionPlanBean}" />
<pui:pension_plan_salary pensionPlanBean="#{pensionPlanBean}" />
<pui:pension_plan_investments pensionPlanBean="#{pensionPlanBean}" />
<pui:pension_plan_benefit_types benefitTypes="#{pensionPlanBean.benefitTypesViewData}" />
<div class="buttons">
<!-- Irrelevant -->
</div>
</cc:implementation>
</ui:composition>
Take the pension_plan_benefit_types composite component for example. Its interface prescribes that an attribute by the name benefitTypes is to be given by the client. If a client wants just this part of the screen to be overwritten by different content than the standard implementation would so, we need a place to overwrite this somewhere.
Also note, that the core does not know about the namespaces that the (optional) extension provides. The core doesn't really care, as long as the interface of the composite is stable and doesn't require changes.
As a last resort, the following has been tried (pseudo code):
<ui:composition
xmlns="http://www.w3.org/1999/xhtml"
xmlns:cc="http://java.sun.com/jsf/composite"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:pui="http://java.sun.com/jsf/composite/pui">
<cc:interface>
<cc:attribute name="benefitTypes" required="true" type="com.foo.bar.PensionPlanBenefitTypesViewData" />
</cc:interface>
<cc:implementation>
<ui:include src="/resources/pui/markup/pension_plan_benefit_types_markup.xhtml" />
</cc:implementation>
</ui:composition>
Where the idea is, that the javax.faces.view.facelets.ResourceResolver will come to our rescue.
It 'kind of works', but depending on the implementation we have to write for the composite components, we run into all kinds of issues in the infamous build,- vs rendertime department of the JSF lifecycle. It basically does not work the way we would expect it to.
The big question now is:
Is there a way in which we have both a stable contract/namespace and have multiple implementations that are dynamically resolved?
Hope someone can shed some light on this, thanks for your input.
Kind regards,
Rens
This kind of situations has been addressed in JSF 2.2 with the resource library contract feature. With that feature, it is possible to have multiple implementations of the same composite component according to its localization and active contracts. Note that the localization / contracts are active per view.
But the option that maybe suits you better is use:
<ui:include src="#{...}">
or
<ui:decorate template="#{...}">
And provide the template name from a managed bean or from the composite component class itself (cc:interface componentType=...). I would recomend use the last version of MyFaces Core in this case, because its algorithm has been optimized specifically for these cases (small view state size and fast performance). I don't think you need to deal with ResourceResolver logic here.
We have extended the ResourceHandlerWrapper in such a way that the classpath will be scanned (first) when xhtml resources from WEB-INF/resources are requested to be loaded.
By defining an explicit classpath in a MANIFEST.MF file, we can let the extension jar files take precedence over the standard implementation. By doing so, we can programmatically generate additional content too, that can be shown in the UI to the developer (when running in development mode) to let him/her know that an 'overriding' implementation could be written in the extension project.

Replace <c:if> and fn:toUpperCase() with JSF-tags

This example is from a book on JSF. The excercise is to refactor the following Facelets code while eliminating <c:if> and fn:toUpperCase(). Usage of <c:forEach> is allowed.
#{myBean.numbers} returns String["one","two","three"]
As the book is on JSF and not on Java, I suppose the existing Java-code is not to be touched. But I can't think of another way to do this solely in Facelets.
<c:forEach var="item" items="#{myBean.numbers}">
<c:if test="#{not fn:endsWith(item,'o')}">
#{item}
</c:if>
<c:if test="#{fn:endsWith(item,'o')}">
#{fn:toUpperCase(item)}
</c:if>
</c:forEach>
Only thing I can think of is using a converter that conditionally uses String#toUpperCase() and then I still do not understand why use of <c:forEach> should still be allowed:
<ui:repeat var="item" value="#{myBean.numbers}">
<h:outputText value="#{item}" converter="conditionalConverter"/>
</ui:repeat>
Is there a more "Facelets way" to do this (and still a need to use <c:forEach>)?
UPDATE:
Instead of <c:if> one could still use e.g. <h:outputPanel> and it's rendered-attribute, but there is still no Java-less replacement for fn:toUpperCase().
I am asking for learning purposes only. I suppose the <ui:repeat>-solution with a converter is the cleanest and represents most how JSF is supposed to be used. Do you think so, too?
As to <c:if>, the JSF alternative to JSTL <c:if> is the rendered attribute on any component. For example, <h:panelGroup> or <h:outputText>. Those components doesn't generate additional markup if there are no attribtues specified which should end up in HTML, like id or styleClass, otherwise they generate a <span>.
Here's an example of both:
<h:panelGroup rendered="#{not fn:endsWith(item,'o')}">
#{item}
</h:panelGroup>
<h:outputText value="#{fn:toUpperCase(item)}" rendered="#{fn:endsWith(item,'o')}" />
As to fn:toUpperCase(), JSF has no alternative. I'm not sure why you would need a JSF alternative as it's essentially not a tag, but a simple EL function which is perfectly usable in both JSTL and JSF tags. In any case, you could if necessary throw in CSS text-transform: uppercase. As this takes place entirely client side, your only problem may be the browser support.
<h:outputText value="#{item}" style="text-transform: uppercase" />
(note: this is just an example, the normal practice is to put styles in its own .css file which you load by <h:outputStylesheet>)
<h:outputText value="#{item}" styleClass="uppercased" />
I suppose the -solution with a converter is the cleanest and represents most how JSF is supposed to be used. Do you think so, too?
I'm a big fan of "Use the right tool for the job". Use JSTL tags to conditionally build the JSF component tree. Use JSF components to generate HTML. That's it. See also JSTL in JSF2 Facelets... makes sense?

wrong ids when render h:panelGroup's inside c:forEach

I have page where I render some h:panelGroup panels. Those panels are realized as plugins registered in a plugin registry on startup.
Part of the plugins api is a custom jsf component where I get the registered plugins for extension point and include their facelet templates by path:
<c:forEach items="#{pluginRegistry.getPlugins(point)}" var="extension">
<ui:include src="#{extension.path}" />
</c:forEach>
The page where I include the panels looks like:
<h:panelGrid id="dashboard" columns="3">
<cmf:insertPageFragments point="dashboardExtensionPoint" />
</h:panelGrid>
For every panel there are facelet templates like the one below:
<rich:panel id="caseDetailsPanel" header="panel label">
<!-- panel content -->
</rich:panel>
Now, the problem is that the very first panel in the list returned by the pluginsRegistry is rendered in the page with the provided id like formId:caseDetailsPanel for example. The rest of them have generated ids like formId:j_idt223 !!! Obviously if I want to rerender some of the panels, I can't do that.
That happens when environment is jboss AS 7.1 with JSF 2.1, richfaces 4.2.3.Final.
When deployed on jboss-eap-6.1 everything looks fine but for now I can't use this jboss version.
Any suggestions on how to workaround this issue?
There can not be multiple JSF components with the same ID. Each JSF component must have an unique ID. When dynamically creating JSF components using JSTL, you need to manually assign and ensure an unique ID, otherwise JSF will discard the provided ID and autogenerate an unique ID.
There are several ways to achieve this, depending on the concrete functional requirement and the existing code.
Use use the iteration index of <c:forEach>.
<c:forEach ... varStatus="loop">
...
<rich:panel id="caseDetailsPanel_#{loop.index}" ...>
This will generate caseDetailsPanel_0, caseDetailsPanel_1, etc depending on the current iteration index.
Use the unique identifier of the currently iterated item. It isn't clear based on the information provided so far if you have any, so here's just a fictive example assuming that the class behind #{extension} has an id property representing the technical DB identifier.
<c:forEach ... var="extension">
...
<rich:panel id="caseDetailsPanel_#{extension.id}" ...>
Wrap #1 or #2 if necessary in a <f:subview> with an unique identifier, so that you don't need to modify the includes.
<c:forEach ... varStatus="loop">
<f:subview id="panel_#{loop.index}">
<ui:include ... />
The <f:subview> creates a new NamingContainer around it, so you end up getting formId:panel_0:caseDetailsPanel, formId:panel_1:caseDetailsPanel and so on.
A completely different alternative would be to use <ui:repeat> instead of <c:forEach>. The <ui:repeat> does not run during view build time, but during view render time. This way there's physically only one <rich:panel id="caseDetailsPanel"> component in the component tree which is reused multiple times during generating HTML whereby JSF will take care of generating the right IDs with the <ui:repeat> index like so formId:repeatId:0:caseDetailsPanel. However, this in turn may cause trouble with <ui:include> as it also runs during view build time and thus can't get the #{extension} at hands.

widgetVar name collision in Primefaces in multiple cc:renderFacet

I have composite component, in which I have toolbar and datatable. I also defined facet which contains a form for manipulating data from datatable. Users define that facet for different kinds of data. Now, I have problem because I render that facet multiple times and now I have collisions for widgetVar names for Primefaces components. It is no possible to use insertChildren multiple times so I think this is only possible solution. Also I wouldn't like to force users of component to define 10 facets and write ui:include 10 times. Is there any other way to insert some facelet code in composite component, or is there any way to pass parameter to facet, and use that parameter to dynamically create widgetVar?
OK, after some time I just didn't succeeded to do what I wanted. First I had some composite component like this:
<cc:interface>
<!-- Attributes definition -->
<cc:facet name="form"/>
</cc:interface>
<cc:implementation>
<p:dialog><f:subview id="detailSubview1"><cc:renderFacet name="form"/></f:subview></p:dialog>
<p:dialog><f:subview id="detailSubview2"><cc:renderFacet name="form"/></f:subview></p:dialog>
<!-- There is some more renderFacets but this is enough -->
</cc:implementation>
If I have for example p:selectOneMenu inside the form, without any widgetVar definitions, all will be with same name for widgetVar and this is a problem.
So, I changed this completely and I will transform this composite component to ui:composition and decorate it in my page. In that case widget vars are generated as I want, with different names, because they are in different naming containers.
A widgetVar is in fact used in JavaScript to identify the component. Therefor a widgetVar must be unique in a page. You'll have to declare it yourself.
If you want to create a custom component, as I think might suit you better than ui:define/ui:include, you might want to do something like this:
Say we want to create a component that renders a p:commandButton and a h:outputText with the same value (for whatever reason). You create a XHTML page in directory [deployed-root]/resources/example, named customComponent.xhtm:
<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://java.sun.com/jsf/composite">
<c:interface>
<c:attribute name="text" required="true" />
</c:interface>
<c:implementation>
<h:outputText value="#{cc.attrs.text}" />
<p:commandButton value="#{cc.attrs.text}" />
</c:implementation>
</html>
Then to use this in another page you'll have to define the namespace xmlns:e="http://java.sun.com/jsf/composite/example", and then you can refer to the custom component like this: <e:customComponent text="some text here"/>.
It should also be noted that it is bad practice to declare forms in custom components. This affects flexibility of use drastically since forms cannot be nested.
PrimeFaces can generate wigetVars so you don't have to.
From the 3.4 User's Guide:
<p:dialog id="dlg">
<!-- contents -->
</p:dialog>
<p:commandButton type="button" value="Show" onclick="#{p:widgetVar('dlg')}.show();"/>
This is designed to work in naming containers, so it should work just fine in composite components, <ui:repeat/>, <h:dataTable/>, etc.

Resources