How to use f:importConstants in composite component? - jsf

What is the best way to use f:importConstants inside of a composite component?
You can't place f:metadata there, so what is the best workaround here?
With Omnifaces and o:importConstants in JSF 2.2, that was no problem, it was allowed everywhere, even in composite component.
Thanks in Advance :)

Since <f:importConstants> must be a child of <f:metadata> (which in turn must be a child of <f:view>), it must use same compositing pattern as described in the official documentation:
The implementation must allow templating for this element according
to the following pattern.
template client XHTML view, view01.xhtml
<ui:composition template="template.xhtml">
<ui:define name="metadata">
<f:metadata>
<f:viewParam name="id"/>
</f:metadata>
</ui:define>
<ui:define name="content">
<h1>The big news stories of the day</h1>
</ui:define>
</ui:composition>
Note line 4. The page author must ensure that the <f:metadata> element does not
appear on a template or included page. It must reside on the root page that
corresponds to the viewId.
The template page, template.xhtml
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xml:lang="en" lang="en">
<body>
<f:view>
<ui:insert name="metadata"/>
<div id="container">
<ui:insert name="content"/>
</div>
</f:view>
</body>
</html>

Related

Unable to use f:metadata f:viewAction from inside components [duplicate]

This question already has an answer here:
When using <ui:composition> templating, where should I declare the <f:metadata>?
(1 answer)
Closed 5 years ago.
In the following page i am not able to load automobileLists since the method to populate it is outside the component in a f:metadata. I have a nullPointerException error.
Partial code :
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:p="http://primefaces.org/ui"
xmlns:f="http://xmlns.jcp.org/jsf/core">
<h:head>
<title>title</title>
</h:head>
<f:metadata>
<f:viewAction action="#{primeAutomobileController.populateAutomobileFieldList}"/>
</f:metadata>
<ui:composition template="layout/template.xhtml">
<ui:define name="content">.....................
The only way for me to load it is to scope the primeAutomobileController to session instead of the original request, and call the method from a preceding page through a button, i would like it to load at the starting of the page instead withouth calling it previously. The method in question :
public void populateAutomobileFieldList(){
List<String> automobileFieldSource = new ArrayList<>();
List<String> automobileFieldTarget = new ArrayList<>();
automobileFieldSource.add("Make");
automobileFieldSource.add("Model");
automobileFieldSource.add("Year");
automobileFieldSource.add("Description");
setAutomobileList(new DualListModel<>
(automobileFieldSource, automobileFieldTarget));
}
Partial index.xhtml page where f:metadata gets loaded
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:p="http://primefaces.org/ui"
xmlns:f="http://xmlns.jcp.org/jsf/core">
<h:head>
<title>title</title>
</h:head>
<f:metadata>
<f:viewAction action="#{primeAutomobileController.loadAutomobiles}"/>
<f:viewAction action="#{primeAutomobileController.populateAutomobileFieldList}"/>
</f:metadata>
<ui:composition template="layout/template.xhtml">
<ui:define name="content"> ......................
Here both methods in f:metadata get properly loaded, like it's shown in an example in a video tutorial i'm following, but when it's the same exact code in a differe xhtml it doesn't work.
The documentation of metadata tag shows how it must be done when using templating (how the template must look like and how to use it in the template client) :
The implementation must allow templating for this element according to
the following pattern.
template client XHTML view, view01.xhtml
<ui:composition template="template.xhtml">
<ui:define name="metadata">
<f:metadata>
<f:viewParam name="id"/>
</f:metadata>
</ui:define>
<ui:define name="content">
<h1>The big news stories of the day</h1>
</ui:define>
</ui:composition>
Note line 4. The page author must ensure that the <f:metadata> element
does not appear on a template or included page. It must reside on the
root page that corresponds to the viewId.
The template page, template.xhtml
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xml:lang="en" lang="en">
<body>
<f:view>
<ui:insert name="metadata"/>
<div id="container">
<ui:insert name="content"/>
</div>
</f:view>
</body>
</html>
The page author is not required to use templating, but if they do, it
must be done as shown above

Test if a jsf template facelet content is defined by a template client using ui:define [duplicate]

I am wondering if it is possible to know if ui:insert was defined in the ui:composition.
I know that I can do it using separate ui:param, but just wanted to do it without in order to keep it simple and less error prone.
Example :
Template
...
<ui:insert name="sidebar" />
<!-- Conditionnaly set the class according if sidebar is present or not -->
<div class="#{sidebar is defined ? 'with-sidebar' : 'without-sidebar'}">
<ui:insert name="page-content" />
</div>
...
Page 1
...
<ui:define name="sidebar">
sidebar content
</ui:define>
<ui:define name="page-content">
page content
</ui:define>
...
Page 2
...
<ui:define name="page-content">
page content
</ui:define>
...
ui:param is for me the best way to go. It's just a matter of using it the right way. As a simple example, I define a param here to specify wether there's a sidebar or not. Keep in mind you can define a default insertion definition in the template, so just declare it inside:
template.xhtml
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html">
<ui:insert name="sidebar">
<!-- By default, there's no sidebar, so the param will be present.
When you replace this section for a sidebar in the client template,
the param will be removed from the view -->
<ui:param name="noSideBar" value="true" />
</ui:insert>
<div class="#{noSideBar ? 'style1' : 'style2'}">
<ui:insert name="content" />
</div>
</ui:composition>
Then couple of views here, one using the sidebar and the other with no sidebar. You can test it and see how the style changes in the browser. You'll notice there's no value for #{noSideBar} in the second one, which will evaluate to false in any EL conditional statement.
page1.xhtml
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets" template="/template.xhtml">
<ui:define name="content">
No sidebar defined? #{noSideBar}
</ui:define>
</ui:composition>
page2.xhtml
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets" template="/template.xhtml">
<ui:define name="sidebar" />
<ui:define name="content">
No sidebar defined? #{noSideBar}
</ui:define>
</ui:composition>
This way you only need to worry about including the sidebar or not in the client view.

ICEfaces configured for view /index.xhtml but h:head and h:body components are required

I am trying to integrate the ICEFaces ACE component library in my project. I've the following view:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core">
<head>
<h:outputStylesheet library="org.icefaces.component.skins"
name="rime.css" />
<f:loadBundle basename="resources.application" var="msg" />
<title>
<h:outputText value="#{msg.templateTitle}" />
</title>
</head>
<body>
<div id="content">
<h:form>
<ace:dataTable var="user" value="#{userBean.users}"
paginator="true" rows="50" selectionMode="multiple">
<ace:column headerText="users">
<ace:row>#{user}</ace:row>
</ace:column>
</ace:dataTable>
</h:form>
</div>
</body>
</html>
Unfortunately apparently there is no JavaScript / CSS loaded, so the components are not displayed properly. Moreover, the server logs this:
ICEfaces configured for view /index.xhtml but h:head and h:body components are required
Is this related?
You need to use JSF <h:head> and <h:body> components instead of plain HTML <head> and <body>. This way JSF and any JSF component library will be able to programmatically auto-include CSS/JS resources in there.
E.g.
<!DOCTYPE html>
<html lang="en"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core">
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
>
<f:loadBundle basename="resources.application" var="msg" />
<h:head>
<title>#{msg.templateTitle}</title>
</h:head>
<h:body>
...
</h:body>
</html>
Note that this way you also don't need that <h:outputStylesheet> anymore.
See also:
One or more resources has the target of 'head' but not 'head' component has been defined within the view
Unrelated to the concrete problem, you'd better declare resources.application as <resource-bundle> in faces-config.xml, so that you don't need to repeat it over all views. Also note that you don't necessarily need <h:outputText> over all place. The <head> and all of above also indicates that you're learning JSF based on a JSF 1.x targeted tutorial instead of a 2.x targeted one. Make sure that you're using the right resources to learn.

How to include common content into multiple level template page

I am trying include a common page into a template but all I get is a blank page without error.
common.xhtml actually has the content that indicate in the template.xhtml. It seems the template.xhtml doesn't recognize the two level include.
template.xhtml
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:s="http://jboss.com/products/seam/taglib"
xmlns:c="http://java.sun.com/jstl/core"
xmlns:ub="http://jboss.com/products/seam/ub-taglib"
xmlns:rich="http://richfaces.ajax4jsf.org/rich">
<head>
<ui:insert name="css" />
<ui:insert name="header" />
</head>
<body>
<ui:insert name="body" />
</body>
</html>
custom.xhtml
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:s="http://jboss.com/products/seam/taglib"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:rich="http://richfaces.ajax4jsf.org/rich"
xmlns:a4j="https://ajax4jsf.dev.java.net/ajax"
xmlns:c="http://java.sun.com/jstl/core"
template="template.xhtml">
<ui:define name="css">
<link rel="stylesheet" type="text/css" href="/custom.css/>
</ui:define>
<ui:include src="common.xhtml" />
</ui:composition>
common.xhtml
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:s="http://jboss.com/products/seam/taglib"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:rich="http://richfaces.ajax4jsf.org/rich"
xmlns:a4j="https://ajax4jsf.dev.java.net/ajax"
xmlns:c="http://java.sun.com/jstl/core"
template="template.xhtml">
<ui:define name="header">
<h1>header</h1>
</ui:define>
<ui:define name="body">
<table><tr><td>Table</td></tr></table>
</ui:define>
</ui:composition>
This indeed won't work. The <ui:define> is supposed to be used in a template client (i.e. a page with <ui:composition template="...">), not in an include file (i.e. a page with <ui:composition> without template). You can however just "extend" from existing master templates.
Remove from custom.xhtml:
<ui:include src="common.xhtml" />
Change in common.xhtml
template="custom.xhtml"
And open common.xhtml instead of custom.xhtml in browser.
See also:
How to include another XHTML in XHTML using JSF 2.0 Facelets?
Unrelated to the concrete problem, to prevent the enduser form being able to open custom.xhtml or template.xhtml directly in browser, it's recommended to move them into the /WEB-INF folder. Further, are you aware of the <h:head> and <h:outputStylesheet> components? I suggest to make use of them. Also, having a <h1> to ultimately end up in <head> makes no sense. Perhaps you meant the <ui:insert name="header"> to be inside <body>? Further, you could easily put that <h1> in the template so that you don't need to repeat them in every template client.
/WEB-INF/templates/template.xhtml
<html ...>
<h:head>
</h:head>
<h:body>
<ui:insert name="header" />
<ui:insert name="body" />
</body>
</html>
/WEB-INF/templates/custom.xhtml (CSS file is placed in /resources folder)
<ui:composition ... template="/WEB-INF/templates/template.xhtml">
<ui:define name="header">
<h1><ui:insert name="custom-header" /></h1>
</ui:define>
<ui:define name="body">
<h:outputStylesheet name="custom.css" target="head" />
<ui:insert name="custom-body" />
</ui:define>
</ui:composition>
/page.xhtml
<ui:composition ... template="/WEB-INF/templates/custom.xhtml">
<ui:define name="custom-header">
header
</ui:define>
<ui:define name="custom-body">
<table><tr><td>Table</td></tr></table>
</ui:define>
</ui:composition>
See also:
Which XHTML files do I need to put in /WEB-INF and which not?
How to reference CSS / JS / image resource in Facelets template?

JSF Javascript failure - myfaces not defined

I'm working on a web solution using myfaces and primefaces. We have several pages in our solution, and some of the get this mystical error myfaces not defined because there is a javascript file that is not included on the page, namely the jsf.js file:
<script type="text/javascript" src="/driwkraft-hig/javax.faces.resource/jsf.js.xhtml?ln=javax.faces&stage=Development">
The error occurs when clicking on certain commandlinks on the page, where the generated javascript has been set to onClick="myfaces.oam.submitForm...
Now, I understand that this is something that the JSF framework adds to the page based on some mystical criteria which I fail to understand. There are pages that appear to be equal with regards to what elements are used, and it succeeds on one and fails on the other.
I have tried to create a test-file where I copied content of one of the failing pages and then removed parts until it would work to figure out what was the source of the problem, but this did not give me anything. My next hunch is that it might be some configuration-error somewhere. But I am completely and utterly blank as to where to start.
I understand I should probable add some code or xml in to this question, but I cannot post the entire solution so I think it is best to do so upon request. Would the web.xml be useful? How about the faces-config.xml?
Any guidance and thoughts are much appreciated!
Edit - adding template
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets">
<ui:insert name="metadata" />
<h:head>
....
<title>
<ui:insert name="title">
....
</ui:insert>
</title>
</h:head>
<h:body>
....
<ui:insert name="content">
....
</ui:insert>
...
</h:body>
</html>
Edit - adding template client
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui"
xmlns:dp="http://java.sun.com/jsf/composite/dapsys">
<ui:composition template="/templates/default.xhtml">
<ui:define name="title">TITLE</ui:define>
<ui:define name="metadata">
<f:metadata>
<f:viewParam name="customerId" value="#{CustomerController.customerId}">
</f:viewParam>
<f:viewParam name="edit" value="#{CustomerController.edit}">
</f:viewParam>
<f:viewParam name="activeTab" value="#{CustomerController.activeTab}">
</f:viewParam>
</f:metadata>
</ui:define>
<ui:define name="content">
...
</ui:define>
</ui:composition>
</html>
It's auto-included if there's a <h:head> in the template which automatically renders CSS/JS dependencies from UIViewRoot#getComponentResources() which are added via #ResourceDependency annotation on the JSF component.
Those problem symptoms suggests that there's no <h:head> in the template, but a plain <head>. Therefore JSF is unable to auto-include CSS/JS resource dependencies which in turn causes this JS error.
To fix this problem, just make sure that there's a <h:head> instead of <head> in the template.
<!DOCTYPE html>
<html lang="en"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets">
<h:head> <!-- Look here. -->
<title>Blah</title>
</h:head>
<h:body>
<h1>Blah</h1>
<p>Blah blah.</p>
</h:body>
</html>

Resources