Linking JSF inputText with backing bean's field without showing its value - java

I have backing bean like this:
#ManagedBean
#SessionScoped
public class TestBean {
private String testString;
public String getTestString() {
return testString;
}
public void setTestString(String testString) {
this.testString = testString;
}
}
And my xhtml page pretty simple too:
<?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://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
>
<h:head></h:head>
<h:body>
<h:form>
<h:inputText value="#{testBean.testString}"/>
<h:commandButton action="#{testController.testAction}"/>
</h:form>
</h:body>
</html>
Everything I want - to render my h:inputText element without value (empty).
I'm new to JSF, so, could you help me?
With best regards!
UPD!
It's simplified code, I'm using testString in other places and testString have value, which I want to hide! And I want to keep this value.

Provided that it's really a request/view scoped bean, you're likely victim of browser's builtin autocomplete/autofill feature. You can turn it off by adding autocomplete="off" to the input component in question.
<h:inputText ... autocomplete="off" />
Note again that it's not JSF who has filled the inputs, but the webbrowser itself. Clear the browser cache and you'll see that the browser won't do it anymore. Depending on browser make/version you can also reconfigure it to autocomplete a bit less eagerly.
Update: as per your question update, your bean turns out to be session scoped. This is not the normal scope for request/view based forms. A session scoped bean instance is shared across all browser windows/tabs (read: all requests/views) in the same HTTP session. You usually store only the logged-in user and its preferences (language, etc) in the session. You will only get a brand new instance when you shutdown and restart the entire browser, or use a different browser/machine.
Change it to be request or view scoped. In this particular simple example, the request scope should suffice:
#ManagedBean
#RequestScoped
See also:
How to choose the right bean scope?
Update 2 based on the comment,
Oh, you right, it's better for me to use #RequestScoped. But it doesn't resolve my problem - I want to keep this value, but I don;t want to show it in textInput. This value is important in context of request-response cycle.
the concrete functional requirement is now much more clear (in future questions, please pay attention to that while preparing the question, I had no idea that you was initially asking it like that). In that case, use a view scoped bean with 2 properties like this:
#ManagedBean
#ViewScoped
public class TestBean {
private String testString;
private String savedTestString;
public void testAction() {
savedTestString = testString;
testString = null;
}
// ...
}
You can alternatively also store it in the database or a property of an injected managed bean which is in turn actually in the session scope, for example.

You should bind the input text to some other field in your backing bean. And if you want to use that field for yourtestString, copy the entered value to testString in the testAction method.
<h:form>
<h:inputText value="#{testBean.copyTestString}"/>
<h:commandButton action="#{testController.testAction}"/>
</h:form>
public String testAction()
{
testString = copyTestString;
return "destinationPage";
}

Some Browsers ignore autocomplete - it can help to put autocomplete in form tag:
<h:form autocomplete="off">

Related

JSF Binding component update before actionListener is called [duplicate]

I am using datatable on page and using binding attribute to bind it to my backing bean. This is my code :-
<?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://java.sun.com/jsf/html"
xmlns:p="http://primefaces.prime.com.tr/ui">
<h:head>
<title>Facelet Title</title>
</h:head>
<h:body>
<h:form prependId="false">
<h:dataTable var="item" value="#{testBean.stringCollection}" binding="#{testBean.dataTable}">
<h:column>
<h:outputText value="#{item}"/>
</h:column>
<h:column>
<h:commandButton value="Click" actionListener="#{testBean.action}"/>
</h:column>
</h:dataTable>
</h:form>
</h:body>
</html>
This is my bean :-
package managedBeans;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.component.html.HtmlDataTable;
#ManagedBean(name="testBean")
#ViewScoped
public class testBean implements Serializable {
private List<String> stringCollection;
public List<String> getStringCollection() {
return stringCollection;
}
public void setStringCollection(List<String> stringCollection) {
this.stringCollection = stringCollection;
}
private HtmlDataTable dataTable;
public HtmlDataTable getDataTable() {
return dataTable;
}
public void setDataTable(HtmlDataTable dataTable) {
this.dataTable = dataTable;
}
#PostConstruct
public void init(){
System.out.println("Post Construct fired!!");
stringCollection = new ArrayList<String>();
stringCollection.add("a");
stringCollection.add("b");
stringCollection.add("c");
}
public void action(){
System.out.println("Clicked!!");
}
}
Please tell me why is the #PostConstruct firing each and every time i click on button? It should fire only once as long as i am on same page beacause my bean is #ViewScoped. Further, if i remove the binding attribute then everything works fine and #PostConstruct callback fires only once. Then why every time when i use binding attribute? I need binding attribute and want to perform initialisation tasks like fetching data from webservice, etc only once. What should i do? Where should i write my initialisation task?
Interesting, when you're using component binding on a view scoped bean, the view scope breaks.
I am not sure if that is a bug in JSF2, I would have to read the entire JSF2 specification first. As far now your best bet is to drop the component binding for now and pass the selected item via new EL 2.2 method argument syntax:
<h:dataTable var="item" value="#{testBean.stringCollection}">
<h:column>
<h:outputText value="#{item}"/>
</h:column>
<h:column>
<h:commandButton value="Click" action="#{testBean.action(item)}"/>
</h:column>
</h:dataTable>
See also:
How can I pass selected row to commandLink inside dataTable?
Invoke direct methods or methods with arguments / variables / parameters in EL
Benefits and pitfalls of #ViewScoped
Update (Dec 2012): this is indeed a bug in JSF2. It's a chicken-egg issue. The view scoped beans are stored in the JSF view state. So the view scoped beans are only available after restore view phase. However, the binding attribute runs during restore view phase, while the view scoped beans are not available yet. This causes creation of a brand new view scoped bean instance, which is then later replaced by the real view scoped bean which was stored in the restored JSF view state.
This is reported as JSF issue 1492 and JSF spec isssue 787 which will be fixed for JSF 2.2. Until then, your best bet is to use binding on request scoped beans exclusively, or to look for alternate ways for the particular functional requirement.
Update (Mar 2015): The JSF 2.2 fix was backported to Mojarra 2.1.18. So if you're still using JSF 2.0/2.1, you'd best upgrade to at least that version. See also a.o. What is component binding in JSF? When it is preferred to be used? and JSTL in JSF2 Facelets... makes sense?
As other said, I would say that the best thing to do is to drop component binding (you don't need it here).
But I would add that you can achieve the same as you're trying to do in a more object-oriented fashion by using action parameters, like this:
<h:commandButton value="Click" action="#{testBean.action(item)}"/>
... and in your java code:
public void action(Item item){
System.out.println("Clicked!!" + item);
}
If you have a viewscoped bean and if you want to retain values that were entered on the form or don't want postconstruct fired, you should return null from your action method.
If you return some outcome (e.g. invalid) and then point the invalid outcome to the same page using faces-config.xml, then the viewscoped bean gets recreated and thus it causes postconstruct to fire again.
Other solution:
Binding the HtmlDataTable in a request scope bean.
Inject this request scope bean in the view scope bean.
JBoss Seam use this solution for binding JSF componentes to a conversation scope component.
The balusc's answer helped me a lot, i would like to say that i had that bug with mojarra version 2.1.7, i am currently using 2.1.29-01 released in january-2015 and this bug is fixed, my problem was binding a tabview to a viewscoped bean. With this version I dont have that bug and binding and postconstruct is working fine.
I use Jboss 5.2 and i have to use mojarra 2.1.x so i hope this answer help other people in the same situation.
http://mvnrepository.com/artifact/com.sun.faces/jsf-api/2.1.29-01
http://mvnrepository.com/artifact/com.sun.faces/jsf-impl/2.1.29-01

How to use outcome in JSF 2x and keep same url in address bar?

I am quite new in developing website with JSF and PrimeFaces, I spent a lots of hours to research about my problem before post here. Thanks to everyone who spent time to read my question.
Well, I'm using this in my menu template page:
<h:link value="Manage Examination" outcome="/backend/examination/index" />
...
<h:link value="List Examinations..." outcome="/WEB-INF/include/backend/examination/List.xhtml" />
<h:link value="Add Examination..." outcome="/WEB-INF/include/backend/examination/Create.xhtml" />
My WEB-INF folder has this structure like below:
WEB-INF
\--include
\\-----backend
\\------'entity name'
\\\-------'create,read,update,delete.xhtml'
Outside of WEB-INF is my root web page folder, I have backend folder here, and its structure:
webpages
\--WEB-INF
\--backend
\\---'entity name'
\\\---index.xhtml
Inside each html I put these code:
<?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">
<ui:composition 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"
template="/WEB-INF/include/templates/backend.xhtml">
<ui:define name="title">
<h:outputText value="#{appBundle.ExaminationTitle}"/>
</ui:define>
<ui:define name="body">
<ui:include src="/WEB-INF/include/backend/examination/List.xhtml"/>
</ui:define>
</ui:composition>
And my question is:
I didn't configure anything in faces-config.xml so could JSF know if I click to the link ?
How could I keep the url in address bar always be /backend/examination/index even I click to the 'List Examination' or 'Add Examination' link with the outcome to /WEB-INF/include/backend/examination/* ?
NNToan
You are misusing <h:link>.
The value of the 'outcome' attribute should be bound to a path whose root is the main faces context path. The JSF framework will render your h:link with an <a/> tag, so keeping the same address is out of question.
<h:link value="Page 1" outcome="page1.xhtml" />
will be in fact translate into:
Page 1
If you want to perform an action without user redirection you should use a commandLink or a commandButton, returning a String (also take care not to include the faces-redirect parameter in that string).
For instance:
<h:commandLink value="Click here" action="#{YourBean.myAction}"/>
In your backing bean:
public String myAction()
{
// do your stuff here
return ""; // in general return the view you want to be redirected on, "" means "here"
}
1.You don't need to. h:link is rendered as an HTML element. So clicking the link issues simple HTTP GET request to the specified URL, no JSF postback, no action listener and no dynamic navigation, and so nothing to do with the faces-config.xml in this case.
2.You can't. Since this is an HTTP GET request, browser will no way display the target URL.
To preserve the URL you have to make a JSF postback and make dynamic navigation with an action listener method that returns an outcome that is used by the navigation handler.
JSF always makes a postback to the same page and so URL is preserved although a new view is rendered.
<h:form>
<!--When you click the button you navigate to the display Examinations view -->
<!--but URL in the browser address bar does not change-->
<h:commandButton value="Navigate" action="#{bean.displayExaminationsList()}"/>
</h:form>
#ManagedBean
public class Bean {
public String displayExaminationsList() {
//The view that maps to this viewID shall be defined in the faces-config.xml
return "examinationsListViewID";
}
}

JSF 2.1 View scoped managed bean re-created on every refresh

So i have a problem and i kindly need any info on how to resolve this.
We're using JSF 2.1 on JBoss 7.1 and we're using view scoped beans which have tables related to that view. The object represented as a row in that table is pretty big.
On every refresh of those views, a new instance of that bean is created.
To verify that this is happening, i have created a demo example:
<!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:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.org/ui">
<h:head>
</h:head>
<h:body>
<h:outputText value="#{viewScopedBean.i}" />
</h:body>
</html>
this template is then linked to a bean defined like this:
#ManagedBean
#ViewScoped
public class ViewScopedBean {
private int i = 0;
#PostConstruct
public void init(){
System.out.println("Init - " + i);
}
#PreDestroy
public void dest(){
System.out.println("Destroy - " + i);
}
public int getI() {
return i;
}
public void setI(int i) {
this.i = i;
}
}
Every time i refresh the view using the browser refresh button or by simply pressing enter in the browser address field, i clearly see the #PostConstruct method invocation.
If I leave the app alive for a very long time i see no #PreDestroy methods being called, and taking a heap dump shows me that ViewScopedBean has the same number of instances as the number i have reloaded the view, and the appear to remain on the heap even if i destroy the session.
This is a huge problem for me because if 500 users reloads the view with that large table, JBoss dies because it's heap space is full.
Is this the designed behavior of #ViewScoped beans or am i doing something wrong?
View scoped beans live only as long as a user interacts with a current view by returning postbacks to the same view (by returning null/void from UICommand action methods). Returning a current view id from an action method, firing a get request to the same view, refreshing the page, manually entering URL in browser's address bar and the events like these all cause the view to be recreated. Thus, you see view scoped beans reinstantiated on every such action.
ViewScoped beans are created every time the view created. So there it is.
But you complain that if 500 users come to the page JBoss will die. The only scope you can use to prevent that is ApplicationScope. But that is a bad idea.
Everybody will recommend you to use the narrowest scope.
So I think the solution to your problem is not another scope but a "lazy load" algorithm. You should load the table page by page. I don't think everybody will need the whole table at one read.
Here is a good description of scopes.
ManagedBeanScopes
If you want the bean to be destroyed you should choose requestScope. Because viewscoped beans stored in the session.

Component attributes doesn't set after "reRender" on AJAX request

Currently i'm working on some complex web front-end and implement it using:
JSF 1.2
Facelets 1.1.15
RichFaces 3.3.3.Final
I have created a custom JSF component which enables validation of inputText fields using pure JavaScript. This component have only one attribute: type. This attribute is responsible for validation algorithm which will be applied at time when user presses a keyboard key.
At restoreView phase when initial view is created this attribute is set by JSF (actually by Facelets). This means that i have a component class with setter and getter for attribute 'type'. And a 'type' setter called with value specified in xhtml document.
Component object is recreated each time at restoreView phase if i specify them in reRender attribute. But when it is recreated my required attribute type is not set.
It's simply creates new component objects... and it's all. May be i don't understand something and this is normal behavior, but how to get attribute values in this case?
Code:
Simple test page:
<?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:u="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:a="http://richfaces.org/a4j"
xmlns:r="http://richfaces.org/rich"
xmlns:v="http://nobodyhere.ru/jsf/validation">
<head>
<title>Test Page</title>
</head>
<body>
<h:form id="testForm">
<h:inputText id="textInput" value="test">
<v:keyValidator type="time"/>
</h:inputText>
<a:commandButton value="Make AJAX request" reRender="testForm"/>
</h:form>
</body>
</html>
Component class:
public class KeyValidator extends UIComponentBase
{
public KeyValidator()
{
System.out.println("new KeyValidator");
}
public KeyValidatorType getValidatorType()
{
return type;
}
public String getType()
{
return getValidatorType().toString();
}
public void setType(String type)
{
this.type = KeyValidatorType.valueOf(type.toUpperCase());
}
#Override
public String getFamily()
{
return KeyValidator.class.getName();
}
private KeyValidatorType type;
}
When i press "Make AJAX request" button my component is recreated. But attribute 'type' is not set in component.
The main problem starts at renderView phase in component renderer when encodeBegin is called it tries to get this attribute and of course it gets null instead of correct value.
So, the more precise question probably:
How to get attribute values of component on AJAX request at renderView phase?
Any help will be greatly appreciated.
You must override saveState and restoreState in component to save and restore needed attributes.
Good Luck!

Internationalised labels in JSF/Facelets

Does Facelets have any features for neater or more readable internationalised user interface text labels that what you can otherwise do using JSF?
For example, with plain JSF, using h:outputFormat is a very verbose way to interpolate variables in messages.
Clarification: I know that I can add a message file entry that looks like:
label.widget.count = You have a total of {0} widgets.
and display this (if I'm using Seam) with:
<h:outputFormat value="#{messages['label.widget.count']}">
<f:param value="#{widgetCount}"/>
</h:outputFormat>
but that's a lot of clutter to output one sentence - just the sort of thing that gives JSF a bad name.
Since you're using Seam, you can use EL in the messages file.
Property:
label.widget.count = You have a total of #{widgetCount} widgets.
XHTML:
<h:outputFormat value="#{messages['label.widget.count']}" />
This still uses outputFormat, but is less verbose.
You could create your own faces tag library to make it less verbose, something like:
<ph:i18n key="label.widget.count" p0="#{widgetCount}"/>
Then create the taglib in your view dir: /components/ph.taglib.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE facelet-taglib PUBLIC "-//Sun Microsystems, Inc.//DTD Facelet Taglib 1.0//EN" "https://facelets.dev.java.net/source/browse/*checkout*/facelets/src/etc/facelet-taglib_1_0.dtd">
<facelet-taglib xmlns="http://java.sun.com/JSF/Facelet">
<namespace>http://peterhilton.com/core</namespace>
<tag>
<tag-name>i18n</tag-name>
<source>i18n.xhtml</source>
</tag>
</facelet-taglib>
create /components/i18n.xhtml
<?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">
<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"
xmlns:f="http://java.sun.com/jsf/core">
<h:outputFormat value="#{messages[key]}">
<!-- crude but it works -->
<f:param value="#{p0}" />
<f:param value="#{p1}" />
<f:param value="#{p2}" />
<f:param value="#{p3}" />
</h:outputFormat>
</ui:composition>
You can probably find an elegant way of passing the arguments with a little research.
Now register your new taglib in web.xml
<context-param>
<param-name>facelets.LIBRARIES</param-name>
<param-value>
/components/ph.taglib.xml
</param-value>
</context-param>
Just add xmlns:ph="http://peterhilton.com/core" to your views and you're all set!
I've never come across another way of doing it other than outputFormat. It is unfortunately quite verbose.
The only other thing I can suggest is creating the message in a backing bean and then outputting that rather than messageFormat.
In my case I have Spring's MessageSource integrated with JSF (using MessageSourcePropertyResolver). Then, it's fairly easy in your backing beans to get parameterised messages - you just need to know which Locale your user is in (again, I've got the Locale bound to a backing bean property so it's accessible via JSF or Java).
I think parameters - particular in messages - are one thing JSF could really do better!
I have been thinking about this more, and it occurs to me that I could probably write my own JSTL function that takes a message key and a variable number of parameters:
<h:outputText value="#{my:message('label.widget.count', widgetCount)}"/>
and if my message function HTML-encodes the result before output, I wouldn't even need to use the h:outputText
#{my:message('label.widget.count', widgetCount)}
You can use the Seam Interpolator:
<h:outputText value="#{interpolator.interpolate(messages['label.widget.count'], widgetCount)}"/>
It has #BypassInterceptors on it so the performance should be ok.
You can use the Bean directly if you interpolate the messages.
label.widget.count = You have a total of #{widgetCount} widgets.
label.welcome.message = Welcome to #{request.contextPath}!
label.welcome.url = Your path is ${pageContext.servletContext}.
${messages['label.widget.count']} is enougth.
This one works great using Spring:
package foo;
import javax.el.ELContext;
import javax.el.ELException;
import javax.el.ExpressionFactory;
import javax.el.ResourceBundleELResolver;
import javax.faces.context.FacesContext;
import org.springframework.web.jsf.el.SpringBeanFacesELResolver;
public class ELResolver extends SpringBeanFacesELResolver {
private static final ExpressionFactory FACTORY = FacesContext
.getCurrentInstance().getApplication().getExpressionFactory();
private static final ResourceBundleELResolver RESOLVER = new ResourceBundleELResolver();
#Override
public Object getValue(ELContext elContext, Object base, Object property)
throws ELException {
Object result = super.getValue(elContext, base, property);
if (result == null) {
result = RESOLVER.getValue(elContext, base, property);
if (result instanceof String) {
String el = (String) result;
if (el.contains("${") | el.contains("#{")) {
result = FACTORY.createValueExpression(elContext, el,
String.class).getValue(elContext);
}
}
}
return result;
}
}
And...
You need to change the EL-Resolver in faces-config.xml from org.springframework.web.jsf.el.SpringBeanFacesELResolver to
Regards
<el-resolver>foo.ELResolver</el-resolver>
Use ResourceBundle and property files.

Categories