Difference between value and binding - jsf

What is the difference between using value and binding with JavaServer Faces, and when would you use one as opposed to the other? To make it clearer what my question is, a couple of simple examples are given here.
Normally with JSF in the XHTML code you would use "value" as here:
<h:form>
<h:inputText value="#{hello.inputText}"/>
<h:commandButton value="Click Me!" action="#{hello.action}"/>
<h:outputText value="#{hello.outputText}"/>
</h:form>
Then the bean is:
// Imports
#ManagedBean(name="hello")
#RequestScoped
public class Hello implements Serializable {
private String inputText;
private String outputText;
public void setInputText(String inputText) {
this.inputText = inputText;
}
public String getInputText() {
return inputText;
}
// Other getters and setters etc.
// Other methods etc.
public String action() {
// Do other things
return "success";
}
}
However, when using "binding", the XHTML code is:
<h:form>
<h:inputText binding="#{backing_hello.inputText}"/>
<h:commandButton value="Click Me!" action="#{backing_hello.action}"/>
<h:outputText value="Hello!" binding="#{backing_hello.outputText}"/>
</h:form>
and the correspondibg bean is called a backing bean, and is here:
// Imports
#ManagedBean(name="backing_hello")
#RequestScoped
public class Hello implements Serializable {
private HtmlInputText inputText;
private HtmlOutputText outputText;
public void setInputText(HtmlInputText inputText) {
this.inputText = inputText;
}
public HtmlInputText getInputText() {
return inputText;
}
// Other getters and setters etc.
// Other methods etc.
public String action() {
// Do other things
return "success";
}
}
What practical differences are there between the two systems, and when would you use a backing bean rather than a regular bean? Is it possible to use both?
I have been confused about this for some time, and would most appreciate having this cleared up.

value attribute represents the value of the component. It is the text that you see inside your text box when you open the page in browser.
binding attribute is used to bind your component to a bean property. For an example in your code your inputText component is bound to the bean like this.
#{backing_hello.inputText}`
It means that you can access the whole component and all its properties in your code as a UIComponent object. You can do lot of works with the component because now it is available in your java code.
For an example you can change its style like this.
public HtmlInputText getInputText() {
inputText.setStyle("color:red");
return inputText;
}
Or simply to disable the component according to a bean property
if(someBoolean) {
inputText.setDisabled(true);
}
and so on....

Sometimes we don't really need to apply the value of UIComponent to a bean property. For example you might need to access the UIComponent and work with it without applying its value to the model property. In such cases it's good to use a backing bean rather than a regular bean. On the other hand in some situations we might need to work with the values of the UIComponent without any need of programmatic access to them. In this case you can just go with the regular beans.
So, the rule is that use a backing bean only when you need programmatic access to the components declared in the view. In other cases use the regular beans.

Related

JSF reloading ViewParam after commandButton action

I'm using JSF and Primefaces. I have an edit.xhtml page with a f:viewParam receiving an entity id:
<f:viewParam name="id" value="#{backingBean.entity}" converter="entityConverter" />
I have two commandButton, one to submit and save the entity:
<p:commandButton ajax="false" value="#{bundle.save}"
action="#{backingBean.save()}"/>
Another to add an item to a collection of the entity:
<p:commandButton ajax="true" process="#this" value="#{bundle.add}"
actionListener="#{backingBean.addItem()}" />
This is my BackingBean:
#ViewScoped
#Named("backingBean")
public class BackingBean {
#EJB
MyDAO myDAO;
private Entity entity; //with getters and setters
public void addItem() {
entity.getData().add(new Item()); //another entity object
}
public void save(){
myDAO.save(entity);
}
...
}
Also I have an EntityConverter class that invoques the DAO and load the object:
#Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
try {
return myDAO.findById(Entity.class, Long.valueOf(value));
} catch (Exception e) {
return null;
}
}
If I try to add more than one items or if I click on save button, the Entity in the BackingBean class is reloaded by calling the getAsObject method of the converter class.
What I'm doing wrong?
Thanks!
For clarity the normal f:param will always behave that way. I use in all my projects OmniFaces ViewParam which fixes these issues.
Stateless mode to avoid unnecessary conversion, validation and model updating on postbacks
The standard UIViewParameter implementation calls the model setter
again after postback. This is not always desired when being bound to a
view scoped bean and can lead to performance problems when combined
with an expensive converter. To solve this, this component by default
stores the submitted value as a component property instead of in the
model (and thus in the view state in case the binding is to a view
scoped bean).
The standard UIViewParameter implementation calls the converter and
validators again on postbacks. This is not always desired when you
have e.g. a required="true", but the parameter is not retained on form
submit. You would need to retain it on every single command
link/button by . To solve this, this component doesn't call
the converter and validators again on postbacks.

EL expression in JSF f:param name attribute

I tried the following:
Something like the facelet I used:
...
<h:button value="x" outcome="nextpage">
<f:param name="#{myBean.PARAM_NAME}" value="someValue"/>
</h:button>
...
Something like the managed bean I used as a controller for the previous facelet:
#Named(value="myBean")
#ViewScoped
public MyBean implements Serializable
{
private static final String PARAM_NAME = "paramName";
public String getPARAM_NAME()
{ return PARAM_NAME };
#PostConstruct
public void init()
{
String passedParamValue = (String) FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get(
PARAM_NAME );
...
}
}
The advantage of this is : I use the param name in two places. In the facelet and in the managed bean as well. This two places are separated. I sould use constants to reduced the possibility of the mistyping. But it seems the name of the f:param does not evaluate EL expressions. (passedParamValue is always null). But if I directly wire the text 'paramName' to the name attribute, it works fine. Am I right or is there any way to use constants here?

How to keep entity up to date after saving changes in managed bean

Let's assume a simple Jsf example with a xhtml page, a ManagedBean, a service and an JPA entityClass. I have a lot of usecases with the following structure:
Hold an entity in my bean
Do actions on the entity
Do rendering on the updated entity
Some easy example, so everyone will understand
Entity:
public class Entity {
private long id;
private boolean value;
...
// Getter and Setter
}
Dao:
public class EntityService {
// Entity Manger em and other stuff
public void enableEntity(long id) {
Entity e = em.find(id);
e.value = true;
em.persist(e);
}
}
Managed Bean:
#ManagedBean
#RequestScoped/ViewScoped
public class EntityBean() {
#EJB
private EntityService entityService;
private Entity entity;
#PostConstruct
public void init() {
// here i fetch the data, to provide it for the getters and setters
entity = entityService.fetchEntity();
}
public void enableEntity() {
entityService.enableEntity(entity.getId);
}
// Getter and Setter
}
and finally a simple xhtml:
<html>
// bla bla bla
<h:panelGroup id="parent">
<h:panelGroup id="disabled" rendered="#{not EntityBean.entity.value}>
<p:commandButton value="action" action="#{EntityBean.enableEntity}" update="parent" />
</h:panelGroup>
<h:panelGroup id="enabled" rendered="#{EntityBean.entity.value}>
// other stuff that should become visible
</h:panelGroup>
</h:panelGroup>
</html>
What i want to achieve:
Always show the up to date entity in every request!
What i already tried
I tried with a dao-fetch in my getter. But you can read everywhere that this is bad practice, because jsf will call the getter more than once (but for now the only way i can keep them really up to date).
I tried RequestScoped Beans. But the Bean will be created before the action is done, and is not recreated on the update call and the value will be outdated (Makes sense, since this is one request, and the request starts with the click on the button).
I tried ViewScoped Beans and added an empty String return value to my method. My hope was, that this redirection will recreate the Bean after the action was processed. But this was not the case.
I tried to call the refetch function manually after every method i used. But I have some cross bean actions on the same entity (My real entities are way more complex than this example). So the different Beans do not always know, if and when the entity has changed.
My Questions:
Can this be done with any kind of Scope? Let's say that every request will fetch the data from my PostConstruct again.
There must be a better solution than the dao-fetch in the getter method
This seems to be a fundamental problem for me, because getting the up to date data is essential for my app (data is changed often).
Using Primefaces 6.1 and Wildfly 10.x
What do you think about this?
A request scoped bean which will be created for update, too and does only one fetchEntity() per request.
<f:metadata>
<f:viewAction action="#{entityBean.load()}" onPostback="true"/>
</f:metadata>
#ManagedBean
#RequestScoped
public class EntityBean() {
#EJB
private EntityService entityService;
private Entity entity = null;
public void load() {}
public Entity getEntity() {
if(entity == null) {
entity = entityService.fetchEntity();
}
return entity;
}
public void enableEntity() {
entityService.enableEntity(getEntity().getId);
}
// Getter and Setter
}

OmniFaces:SelectItemsConverter not working with PrimeFaces: PickList

I'm trying to use SelectItemsConverter with PrimeFaces Picklist.
XHTML:
<p:pickList id="plUpdateFirma" value="#{bsvttController.dlmFirma}" var="plFirma"
itemLabel="#{plFirma.schluesselFirma}" itemValue="#{plFirma}"
converter="FirmaConverter">
<f:facet name="sourceCaption">
Vorjahr
</f:facet>
<f:facet name="targetCaption">
#{bsvttController.selSaison}
</f:facet>
<p:column>
#{plFirma.schluesselFirma}
</p:column>
</p:pickList>
Converter:
#FacesConverter(value = "FirmaConverter")
public class FirmaConverter extends SelectItemsConverter
{
#Override
public String getAsString(final FacesContext facesContext, final UIComponent component, final Object object)
{
return ((Firma) object).getSchluesselFirma();
}
}
Bean:
#ManagedBean
#ViewScoped
public class BsvttController implements Serializable
{
private DualListModel<Firma> dlmFirma;
private List<Firma> dlmFirmaSource;
private List<Firma> dlmFirmaTarget;
private Firma firma;
#PostConstruct
public void init()
{
dlmFirmaSource = FirmaPersistenz.leseFirmaAlle();
dlmFirmaTarget = new ArrayList<Firma>();
dlmFirma = new DualListModel<>(dlmFirmaSource, dlmFirmaTarget);
}
public DualListModel<Firma> getDlmFirma()
{
return dlmFirma;
}
public List<Firma> getDlmFirmaSource()
{
return dlmFirmaSource;
}
public List<Firma> getDlmFirmaTarget()
{
return dlmFirmaTarget;
}
public void setDlmFirma(DualListModel<Firma> dlmFirma)
{
this.dlmFirma = dlmFirma;
}
public void setDlmFirmaSource(List<Firma> dlmFirmaSource)
{
this.dlmFirmaSource = dlmFirmaSource;
}
public void setDlmFirmaTarget(List<Firma> dlmFirmaTarget)
{
this.dlmFirmaTarget = dlmFirmaTarget;
}
}
While debugging converter I could see that getAsString method is working fine. But after submitting the form both arraylists (dlmFirmaSource and dlmFirmaTarget) are empty.
OmniFaces showcase says that
"The omnifaces.SelectItemsConverter allows you to populate e.g. a drop-down with complex Java model objects as value of f:selectItems and have JSF convert those automatically back without the need to provide a custom converter which may need to do the job based on possibly expensive service/DAO operations."
But in case of PickList component there doesn't exist any f:selectItems tag.
Does SelectItemsConverter even support PickList component?
Does SelectItemsConverter even support PickList component?
No, it doesn't.
Since OmniFaces 1.5, you can use omnifaces.ListConverter or omnifaces.ListIndexConverter for the desired purpose. See also the ListConverter showcase example which also demonstrates the usage on <p:pickList>.
No, the SelectItemsConverter handles conversion of core JSF SelectItem objects for use with various JSF components.
The class DualListModel is a PrimeFaces specific class meant for use with advanced PrimeFaces data components. The workaround of course is to possible use a #PostConstruct method to initialize your DualListModel in the managed bean so that it does not require a converter, or you can simply implement the converter in the traditional way. From the PrimeFaces guide on the converter attribute of Pick List:
An el expression or a literal text that defines a
converter for the component. When it’s an EL
expression, it’s resolved to a converter instance.
In case it’s a static text, it must refer to a
converter id

c:set for bean properties

I'm looking for some piece of code for setting a property in a JSF managed bean. My first idea was something like that:
<c:set var="#{loginBean.device}" value="mobil"></c:set>
That means I want to set the attribute device to the value "mobil" without a button have to been clicked.
Yes, you can use c:set for this purpose.
<c:set value="mobil" target="#{loginBean}" property="device" />
Doc: http://docs.oracle.com/cd/E17802_01/j2ee/javaee/javaserverfaces/2.0/docs/pdldocs/facelets/c/set.html
However, setting a static value rarely makes sense. You might consider to set a default value directly in your managed bean class. Also in terms of maintainability since you can handle constants better in the Java code than in the view layer.
I think you want the JSF tag child tag setPropertyActionListener. You can set this as a child tag in any ActionComponent.
<h:anyActionComponent id="component1">
<f:setPropertyActionListener target="#{loginBean.device}" value="mobil" />
</h:anyActionComponent>
UPDATE:
I originally misunderstood the users problem. They have a page, and they want a property to be set when the page loads. There is a couple ways to do this, but both are a little different. If you want to set a property to a value after every postback then you can use the #PostConstruct annotation on a ManagedBean method.
#PostConstruct
public void initializeStuff() {
this.device = "mobil";
}
Now if I have a ViewScoped or SessionScope bean that needs to be initialized with a default value just once when the page loads then you can set a phase lifecycle event that will run after every postback and check to see if the page should be initialized or not.
mah.xhmtl:
<f:event listener="#{loginBean.initialize()}" type="preRenderView" />
LoginBean:
public void initialize() {
if (this.device == null)
this.device = "mobil";
}
I am not able to Comment: If you need the value to be ready on page on load, you could use Managed Bean to directly initialize value or use its constructor or #PostConstruct to do the same.
#ManagedBean
#ResquestScoped
public class LoginBean {
private String device = "some value";
//Using Constructor
public LoginBean() {
device = getvalueFromSomewhere();
}
//Using PostConstruct
#PostConstruct
public void init() {
device = getvalueFromSomewhere();
}
}
Instead of setting the value in the xhtml file you can set via another ManagedBean. For instance if you have managedBean1 which manages page1.xhtml and managedBean2 which manages page2.xhtml. If page1.xhtml includes page2.xhtml like:
<ui:include src="page2.xhtml"/>
in managedBean1 you can have at the top
#ManagedProperty(value = "#{managedBean2}")
private ManagedBean2 managedBean2;
and in the PostConstruct
#PostConstruct
public void construct() {
managedBean2.setProperty(...);
}
worked for me anyway...

Resources