My JSF Books/Videos My JSF Tutorials OmniFaces/JSF PPTs
JSF 2.3 Tutorial
JSF Caching Tutorial
JSF Navigation Tutorial
JSF Scopes Tutorial
JSF Page Author Beginner's Guide
OmniFaces 2.3 Tutorial Examples
OmniFaces 2.2 Tutorial Examples
JSF Events Tutorial
OmniFaces Callbacks Usages
JSF State Tutorial
JSF and Design Patterns
JSF 2.3 New Features (2.3-m04)
Introduction to OmniFaces
25+ Reasons to use OmniFaces in JSF
OmniFaces Validators
OmniFaces Converters
JSF Design Patterns
Mastering OmniFaces
Reusable and less-verbose JSF code

My JSF Resources ...

Java EE Guardian
Member of JCG Program
Member MVB DZone
Blog curated on ZEEF
OmniFaces is an utility library for JSF, including PrimeFaces, RichFaces, ICEfaces ...

[OmniFaces Utilities] - Find the right JSF OmniFaces 2 utilities methods/functions

Search on blog

Petition by Java EE Guardians

Twitter

miercuri, 23 decembrie 2015

[JSF Page Author Beginner's Guide] JSF <f:attribute/>

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.

Note When you have to deal with cross-field validation, you may want to consider the OmniFaces <o:validateBean/> or the new JSF 2.3 <f:validateWholeBean/>.

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.

See also Mkyong.com.
More resources on Constantin Alin, ZEEF page.

Niciun comentariu :

Trimiteți un comentariu

JSF BOOKS COLLECTION

Postări populare

Follow by Email

Visitors Starting 4 September 2015

Locations of Site Visitors