The <f:attribute/> sets the specified name and attribute on the parent UIComponent.
If the "value" specified is not a literal, it will instead set the ValueExpression on the UIComponent.
Common/basic usage in JSF (I) - assigning supported
attributes (e.g. value and style) to a JSF component (e.g. <h:outputText/>)
(attributes values are hard coded):
<?xml version='1.0' encoding='UTF-8' ?>
<!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:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core">
<h:head>
<title>JSF f:attribute examples</title>
</h:head>
<h:body>
<h:outputText>
<f:attribute name="value" value="Hello
world!"/>
<f:attribute name="style" value="color:blue"/>
</h:outputText>
</h:body>
</html>
Common/basic usage in JSF (II) - assigning
supported attributes (e.g. value and style) to a JSF component
(e.g. <h:outputText/>)
(attributes values are served from a properties file):
<?xml version='1.0' encoding='UTF-8' ?>
<!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:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core">
<h:head>
<title>JSF f:attribute examples</title>
</h:head>
<h:body>
<h:outputText>
<f:attribute name="value"
value="#{msg['HELLO']}"/>
<f:attribute name="style"
value="#{msg['STYLE']}"/>
</h:outputText>
</h:body>
</html>
The properties file has a two entries, as follows:
HELLO = Hello world!
STYLE = color:red
Common/basic usage in JSF (III) - Assigning
supported attributes (e.g. value and style) to a JSF component
(e.g. <h:outputText/>)
(attributes values are served by a managed bean):
<?xml version='1.0' encoding='UTF-8' ?>
<!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:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core">
<h:head>
<title>JSF f:attribute examples</title>
</h:head>
<h:body>
<h:outputText>
<f:attribute name="value"
value="#{myBean.hello}"/>
<f:attribute name="style"
value="#{myBean.style}"/>
</h:outputText>
</h:body>
</html>
And the managed bean is:
package beans;
import javax.enterprise.context.RequestScoped;
import javax.inject.Named;
@Named
@RequestScoped
public class MyBean {
private final
String hello = "Hello world!";
private final
String style = "color:green";
public
MyBean() {
}
public String
getHello() {
return
hello;
}
public String
getStyle() {
return
style;
}
}
The complete application is available
here.
More examples:
Passing parameters or setting
unsupported attributes to a JSF component
The <f:attribute> tag can be used to pass "parameters"
or set unsupported attributes to a JSF component, as shown in the following
code (obviously, the playerName and playerSurname are not command button
supported attributes):
<h:commandButton
actionListener="#{playersBean.parametersAction}">
<f:attribute name="value"
value="Send Rafael Nadal" />
<f:attribute id="playerName"
name="playerNameAttr" value="Rafael"/>
<f:attribute id="playerSurname"
name="playerSurnameAttr" value="Nadal"/>
</h:commandButton>
The PlayersBean is listed below (notice how the
attributes are extracted on server):
package beans;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.enterprise.context.RequestScoped;
import javax.faces.event.ActionEvent;
import javax.inject.Named;
@Named
@RequestScoped
public class PlayersBean {
private final
static Logger logger = Logger.getLogger(PlayersBean.class.getName());
private
String playerName;
private
String playerSurname;
public
PlayersBean() {
}
public String
getPlayerName() {
return
playerName;
}
public void
setPlayerName(String playerName) {
this.playerName = playerName;
}
public String
getPlayerSurname() {
return playerSurname;
}
public void
setPlayerSurname(String playerSurname) {
this.playerSurname = playerSurname;
}
public void
parametersAction(ActionEvent evt) {
playerName = (String)
evt.getComponent().getAttributes().get("playerNameAttr");
playerSurname = (String)
evt.getComponent().getAttributes().get("playerSurnameAttr");
logger.log(Level.INFO, "Name: {0} Surname: {1}", new
Object[]{playerName, playerSurname});
}
}
The complete application is available
here.
Passing extra parameters to a custom validator
In the below example, you can see how <f:attribute/>
can be used to pass extra parameters to a custom validator:
<h4>Select your next opponent:</h4>
<h:form id="racquetForm">
<h:messages/>
<h:selectOneMenu
validator="gameValidator">
<f:selectItem itemValue="Rafael Nadal"
itemLabel="Rafael Nafal"/>
<f:selectItem itemValue="Roger Federer"
itemLabel="Roger Federer"/>
<f:selectItem
itemValue="Novak Djokovic" itemLabel="Novak
Djokovic"/>
<f:attribute
name="msgAttrRafaelNadal" value="'King of clay' cannot be
selected for this game ..."/>
<f:attribute name="msgAttrRogerFederer"
value="'The Maestro' cannot be selected for this game ..."/>
<f:attribute
name="msgAttrNovakDjokovic" value="'Nole' cannot be selected for
this game ..."/>
</h:selectOneMenu>
<h:commandButton value="Select"/>
</h:form>
And, the custom validator is listed below:
package beans;
import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.validator.FacesValidator;
import javax.faces.validator.Validator;
import javax.faces.validator.ValidatorException;
@FacesValidator
public class GameValidator implements Validator {
@Override
public void
validate(FacesContext context, UIComponent component, Object value) throws ValidatorException
{
String
player = value.toString().replaceAll("\\s+", "");
throw new ValidatorException(new
FacesMessage("Response:" + (String)
component.getAttributes().get("msgAttr" + player)));
}
}
The complete application is available
here.
Validating multiple fields (cross-field) using a custom
validator
In the below example, you can see how <f:attribute/>
can be used to validate multiple fields using a custom validator:
<h4>Use 'f:attribute' to validate multiple
components</h4>
<h:form id="registerForm">
<h:panelGrid id="pgId"
columns="3">
<h:outputLabel for="nameId" value="Player name :
" />
<h:inputText id="nameId"
value="#{playersBean.name}" required="true" />
<h:message for="nameId" style="color: red;" />
<h:outputLabel for="surnameId" value="Player surname :
" />
<h:inputText id="surnameId"
value="#{playersBean.surname}" required="true" />
<h:message for="surnameId" style="color: red;"
/>
<h:outputLabel for="bankAccountId" value="Bank account
: " />
<h:inputText id="bankAccountId"
value="#{playersBean.bank}" required="true">
<f:validator
validatorId="bankValidator" />
<f:attribute
name="confirmBankAccountAttr" value="#{confirmBankAccount}"
/>
</h:inputText>
<h:message for="bankAccountId" style="color:
red;" />
<h:outputLabel for="confirmBankAccountId"
value="Confirm bank account : " />
<h:inputText id="confirmBankAccountId"
value="#{playersBean.cbank}"
binding="#{confirmBankAccount}"
required="true" />
<h:message for="confirmBankAccountId" style="color:
red;" />
</h:panelGrid>
<h:commandButton action="done"
value="Send" />
</h:form>
And, the custom validator is listed below:
package beans;
import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.component.UIInput;
import javax.faces.context.FacesContext;
import javax.faces.validator.FacesValidator;
import javax.faces.validator.Validator;
import javax.faces.validator.ValidatorException;
@FacesValidator
public class BankValidator implements Validator {
@Override
public void
validate(FacesContext context, UIComponent component, Object value) throws
ValidatorException {
String
bankAccount = value.toString();
UIInput
uiInputBankAccount = (UIInput)
component.getAttributes().get("confirmBankAccountAttr");
String bankAccountC = uiInputBankAccount.getSubmittedValue().toString();
if ((bankAccount != null) &&
(bankAccountC != null)) {
if (!bankAccount.equals(bankAccountC)) {
uiInputBankAccount.setValid(false);
throw new ValidatorException(new FacesMessage("Bank
account must match bank account confirmation!"));
}
}
}
}
And, the managed bean is:
package beans;
import javax.enterprise.context.RequestScoped;
import javax.inject.Named;
@Named
@RequestScoped
public class PlayersBean {
private
String name;
private
String surname;
private
String bank;
private
String cbank;
public String
getName() {
return name;
}
public void
setName(String name) {
this.name =
name;
}
public String
getSurname() {
return
surname;
}
public void
setSurname(String surname) {
this.surname
= surname;
}
public String
getBank() {
return bank;
}
public void
setBank(String bank) {
this.bank =
bank;
}
public String
getCbank() {
return
cbank;
}
public void
setCbank(String cbank) {
this.cbank =
cbank;
}
}
The complete application is available
here.
Dynamically passing parameters
Another case when the <f:attribute/> tag can
be useful is when dynamically passing parameters in conjunction with UI
components bound to the managed bean using the binding attribute. This is
very useful, especially because there is no solution provided by JSF for
passing parameters to the getters/setters methods of the bound UI components,
as shown in the following code:
<h:form>
<h:inputText
binding="#{playersBean.htmlInputText}" value="#{playersBean.playerNameSurname}">
<f:attribute
name="playerNameAttr" value="Rafael Nadal"/>
</h:inputText>
</h:form>
And the managed bean is:
package beans;
import javax.enterprise.context.RequestScoped;
import javax.faces.component.UIInput;
import javax.inject.Named;
@Named
@RequestScoped
public class PlayersBean {
private
UIInput htmlInputText= null;
public
PlayersBean() {
}
public
UIInput getHtmlInputText() {
return
htmlInputText;
}
public void
setHtmlInputText(UIInput htmlInputText) {
this.htmlInputText = htmlInputText;
}
public String getPlayerNameSurname() {
return (String)
htmlInputText.getAttributes().get("playerNameAttr");
}
}
Now, the value of the <h:inputText/> tag
should contain the value set via the <f:attribute/> tag. Be careful to
use only unique names for the attributes and to not interfere (try to
overwrite) with the default attributes of the UI component.
The complete application is available
here.
Passing extra parameters to PrimeFaces FileUpload component
If you are a fan of
PrimeFaces, then you will probably find
the next example useful. One of the greatest built-in components of PrimeFaces is
the
<p:fileUpload/>
tag, which can be used, obviously, to upload files. Sometimes, besides the
files that will be uploaded, you need to pass some extra parameters, for
example, the files' owner name and surname. Well, the
<p:fileUpload/>
tag doesn't come with a solution for this, but the
<f:attribute/> tag can
be helpful. The following is the code of a classic
<p:fileUpload/> tag
with the
<f:attribute/>
tag:
<h:form>
<p:fileUpload
fileUploadListener="#{fileUploadController.handleFileUpload}"
mode="advanced" dragDropSupport="false"
update="messages"
fileLimit="3"
allowTypes="/(\.|\/)(gif|jpe?g|png)$/">
<f:attribute id="playerName"
name="playerNameAttr" value="Rafael"/>
<f:attribute id="playerSurname"
name="playerSurnameAttr" value="Nadal"/>
</p:fileUpload>
<p:growl
id="messages" showDetail="true"/>
</h:form>
The handleFileUpload() method is responsible for
the upload-specific steps (skipped in the following code), but it can also
access the values passed by the <f:attribute/> tag:
package beans;
import javax.enterprise.context.RequestScoped;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.inject.Named;
import org.primefaces.event.FileUploadEvent;
@Named
@RequestScoped
public class FileUploadController {
public void
handleFileUpload(FileUploadEvent evt) {
String
playerName = (String)
evt.getComponent().getAttributes().get("playerNameAttr");
String playerSurname = (String)
evt.getComponent().getAttributes().get("playerSurnameAttr");
FacesMessage
msg = new FacesMessage("Succesful", evt.getFile().getFileName() +
" is uploaded for " + playerName + " " + playerSurname);
FacesContext.getCurrentInstance().addMessage(null, msg);
}
}
The complete application is available
here.
Set a component renderer from page
Let's suppose that we have two input components as
below:
<h:inputText id="..."
value="..."/>
<h:inputText id="..." value="...
"/>
By default, both of them will be renderer via the
renderer identified by the javax.faces.Text renderer type. But, let's
suppose that we want to use the default renderer for the first input component,
and a custom renderer (provided by us with renderer type, dummy.foo.Text)
for the second input component. Well, we can try to use the rendererType
attribute, but you will notice that this doesn't work.
<h:inputText id="..."
value="..."/>
<h:inputText id="..." value="...
" rendererType="dummy.foo.Text"/>
Bauke
Scholtz (aka BalusC), member of JSF EG , explains: "
It will work. Tooling only doesn't recognize
is because it's not listed in taglib file which the tooling depends on. You can
alternatively use f:attribute for that."
So, until this will work, we can use <f:attribute/>
as below:
<h:inputText id="..."
value="..."/>
<h:inputText id="..."
value="...">
<f:attribute name="rendererType"
value="dummy.foo.Text"/>
</h:inputText>
Using a navigation case to enter in a flow
When you need to use a navigation case to enter in
a flow, you will have to specify the <to-flow-document-id>document_ID</toflow-document-id> statement nested in
the <navigation-case/>
tag. If there is no document ID, that uses <to-flow-document-id/>.
Moreover a <h:button/>
(or <h:link/>)
can be used to enter in such a flow, as follows:
<h:button id="..." value="enter flow" outcome="flow">
<f:attribute
name="to-flow-document-id" value="unique"/>
</h:button>
If you choose to write a programmatic navigation
case, then JSF 2.2 comes with a method named, getToFlowDocumentId(), which
should be overridden for indicating the document ID.
More resources on Constantin Alin, ZEEF page.