How to set a define inside other define - jsf

I'm developing a web application in jboss, seam, richfaces.
I'm using a template(xhtml) as master page of all others and there i set two insert tags. <ui:insert name="head"/>
<ui:insert name="body"/>
The problem is that in pages that use this master page as template, the <ui:define name="head">...</ui:define> must be defined inside the <ui:define name="body">...</ui:define>.
How can i do this?
Basically, what i want is to do the following:
<ui:define name="body">... <ui:define name="head"> <meta name="title" content="#{something.title}" /> </ui:define> ...</ui:define>
the master page must return : <meta name="title" content="#{something.title}" /> on the <ui:insert name="head"/>
Thanks in advance

I don't think facelets work like that. It compiles and reads the template.
So I think you can just define how many definitions you want and dont care about nesting.
ie:
//In your template.xhtml
<ui:insert name="outer">
BLA BLA BLA
<ui:insert name="inner"/>
BLA BLA BLA
</ui:insert>
And when you want to use this template simply:
<ui:define name="outer">
Here you can overwrite outer (This will probably overwrite inner, not sure, you need to test it)
</ui:define>
<ui:define name="inner">
Or you can ONLY overwrite inner here if you want
</ui:define>

You can use <ui:param> in order to define content on each page. For example
in the template:
<meta name="title" content="#{titleParam}" />
in the page that uses the template:
<ui:param name="titleParam" value="customValueForThisPage" />

Related

How to use f:importConstants in composite component?

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>

How can I switch between two ui:compositions in a Facelets file?

In a JSF xhtml file, I would like to be able to choose between two different ui:compositions based on some flag. This is illustrated below using a fictional magic:if tag. How can I do this? In other words, what real tag can I use in place of magic:if?
<magic:if test="showOption1">
<ui:composition template="/option1.xhtml">
<ui:define name="header">Foo</ui:define>
</ui:composition>
</magic:if>
<magic:if test="!showOption1">
<ui:composition template="/option2.xhtml">
<ui:define name="header">Foo</ui:define>
</ui:composition>
</magic:if>
In other words, what real tag can I use in place of magic:if?
There's none. The <ui:composition> is the root element. Nothing can end up higher.
You have 2 options:
Do the switch in template attribute itself.
<ui:composition template="/option#{showOption1 ? 1 : 2}.xhtml">
<ui:define name="header">Foo</ui:define>
</ui:composition>
Use <ui:decorate> inside <ui:composition> instead, this one can be wrapped in a <c:if>.
<ui:composition template="/options.xhtml">
<c:if test="#{showOption1}">
<ui:decorate template="/option1.xhtml">
<ui:define name="header">Foo</ui:define>
</ui:decorate>
</c:if>
<c:if test="#{not showOption1}">
<ui:decorate template="/option2.xhtml">
<ui:define name="header">Foo</ui:define>
</ui:decorate>
</c:if>
</ui:composition>

JSF 2.2: output "jsf.js" and "omnifaces.js" manually to body instead of head

i have a problem with the load-order of javascript-resources in my jsf-project. in my master-template i load all scripts at the bottom of the page:
<h:body>
...
<ui:insert name="scripts">
<h:outputScript name="js/jquery.js" />
<h:outputScript name="js/chart.js" />
<h:outputScript name="js/all.js" />
</ui:insert>
</h:body>
on some pages i use the omnifaces commandscript-tag with a javascript-function defined in all.js:
<o:commandScript name="ALL.selectTypes" action="#{bean.typeSelected}">
i get
ReferenceError: ALL is not defined
the reason is, that at the time jsf.js and omnifaces.js are loaded, all.js isn't loaded yet, because both scripts appear in the head of the document while my own scripts appear at the bottom. when i put my scripts in
<h:head>
instead at the page bottom it works as expected. can i control manually the appearance for these scripts so that they appear like:
<h:body>
...
<ui:insert name="scripts">
<h:outputScript library="javax.faces" name="jsf.js" />
<h:outputScript library="omnifaces" name="omnifaces.js" />
<h:outputScript name="js/jquery.js" />
<h:outputScript name="js/chart.js" />
<h:outputScript name="js/all.js" />
</ui:insert>
</h:body>
the above try doesn't have any effect. jsf.js and omnifaces.js are placed in the head anyway. i also tried with replacing
<h:outputScript>
with
<o:deferredScript>
but can't made it. are there any alternatives? thanks in advance for hints.
You'd better declare ALL namespace in head or perhaps in a general script loaded in head.
<h:head>
...
<script>var ALL = {};</script>
</h:head>
And make sure that all.js itself doesn't override this by another var ALL = {}.
var ALL = ALL || {};

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.

Facelets: how to pass a ui:insert value as an html attribute?

I'm trying to accomplish a small tweak in a Facelets/JSF environment. I know next to nothing how all of it fits together.
I have a value defined on various pages as "title"
<ui:define name="title">PageUID_123</ui:define>
On another page I am referencing this with:
<ui:insert name="title"/>
I can wrap html tags around the insert just fine, but I need to be able to output the value of "title" as an attribute of another element. My end goal is for it to render in html like this:
<meta name="pageid" content="PageUID_123"/>
If I try putting the insert tag in the content="" bit, it throws a parsing error. Is there a way to do this?
I don't have a working environment in front of me, but I believe you don't want to you use <ui:define>, but instead you want to use <ui:param> and then use ${x} or #{x} (or forget which or if it matters) to pull them out.
So, for you example you would have:
<ui:param name="title" value="PageUID_123" />
And then:
<meta name="pageid" content="${title}"/>
My only concern with that is that you are using include to have nice templates, i.e.
template:
<html>
<head>
<meta name="pageid" content="${title}"/>
</head>
<body>
<ui:insert name="content" />
</body>
</html>
Inner page:
<html xmlns="...so many">
<ui:param name="title" value="PageUID_123" />
<ui:define name="content">
<!-- content goes here -->
</ui:define>
</html>
And I really don't know if that will fly...
Edit: You may want to try ${title} or #{title} just for kicks the way you're doing it now, it might Just Work.

Resources