JSF component binding without bean property throwing conversion error - jsf

In a column of a table I've tried to bind a component value to a local scoped EL variable and later on to use that variable as a paramter:
<h:column>
<h:outputLabel value="Enter a quantity to put into the cart" for="qty"/>
<h:inputText id="qty" binding="#{qty}" converter="javax.faces.Number"/>
</h:column>
<h:column>
<h:commandButton value="Put into cart" type="submit"
action="#{shoppingCart.addToCart(product, qty)}"/>
</h:column>
Where product is the current element of the datatable (a list of filtered or unfiltered products that are not in the cart).
Now when trying to add a product to the cart (e.g. with the quantity 12) it throws the following exception:
javax.faces.el.EvaluationException: java.lang.IllegalArgumentException: Cannot convert javax.faces.component.html.HtmlInputText#377c8b02 of type class javax.faces.component.html.HtmlInputText to class java.lang.Integer
at javax.faces.component.MethodBindingMethodExpressionAdapter.invoke(MethodBindingMethodExpressionAdapter.java:101)
at com.sun.faces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:102)
at javax.faces.component.UICommand.broadcast(UICommand.java:315)
at javax.faces.component.UIData.broadcast(UIData.java:1108)
at javax.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.java:790)
at javax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:1282)
at com.sun.faces.lifecycle.InvokeApplicationPhase.execute(InvokeApplicationPhase.java:81)
at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:198)
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:658)
at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1682)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:318)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:160)
at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:734)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:673)
at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:99)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:174)
at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:416)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:283)
at com.sun.enterprise.v3.services.impl.ContainerMapper$HttpHandlerCallable.call(ContainerMapper.java:459)
at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:167)
at org.glassfish.grizzly.http.server.HttpHandler.runService(HttpHandler.java:206)
at org.glassfish.grizzly.http.server.HttpHandler.doHandle(HttpHandler.java:180)
at org.glassfish.grizzly.http.server.HttpServerFilter.handleRead(HttpServerFilter.java:235)
at org.glassfish.grizzly.filterchain.ExecutorResolver$9.execute(ExecutorResolver.java:119)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeFilter(DefaultFilterChain.java:283)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeChainPart(DefaultFilterChain.java:200)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.execute(DefaultFilterChain.java:132)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.process(DefaultFilterChain.java:111)
at org.glassfish.grizzly.ProcessorExecutor.execute(ProcessorExecutor.java:77)
at org.glassfish.grizzly.nio.transport.TCPNIOTransport.fireIOEvent(TCPNIOTransport.java:536)
at org.glassfish.grizzly.strategies.AbstractIOStrategy.fireIOEvent(AbstractIOStrategy.java:112)
at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.run0(WorkerThreadIOStrategy.java:117)
at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.access$100(WorkerThreadIOStrategy.java:56)
at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy$WorkerThreadRunnable.run(WorkerThreadIOStrategy.java:137)
at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:591)
at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.java:571)
at java.lang.Thread.run(Thread.java:745)
I'm using Glassfish 4.1.1 with JSF version 2.2.12.
I'd be grateful for any ideas
CLARIFACATION
As pointed out by BalusC in this question JSF component binding without bean property and others, binding="#{var}" is actually valid XHTML. This way no backing bean is needed and the declared variable is request scoped. I find this option more elegant and hence would like to stick with it.

Instead of binding="#{qty}" (which should be used to bind your input component to a Java instance of your component in a managed bean), use: value="#{shoppingCart.quantityAsInteger}", or if you are working with a list of shopping cart items: value="#{shoppingCartItem.quantityAsInteger}".
Apart from proper value binding this will also give you the benefit of having the quantity as part of your model. Additionally, when the value is bound to an Integer, there is no need to add a converter. JSF will take care of Integer (and some other types) conversion by default.
So, make sure you have a managed bean containing the quantity or a list of cart items which each have a quantity. In case of a list of cart items, you will end up with something like:
ShoppingCart.java
// You will probably already have something like this for your table
private List<ShoppingCartItem> shoppingCartItems;
ShoppingCartItem.java
// Quantity used for binding (add getter and setter).
private Integer quantity;
private Product product;
XHTML
<h:column>
<h:outputLabel value="Enter a quantity to put into the cart" for="qty"/>
<h:inputText id="qty" binding="#{shoppingCartItem.quantity}" />
</h:column>

Try using value attribute instead of binding attribute in h:inputText and use binding attribute on a table component. That way you can access to the selected (clicked) row in a action method: if binding attribute of a table has value #{bean.dataTable}, you can get row data in a method like getDataTable.getRowData().

Though declaring an EL variable is valid XHTML, the component itself is bound to the variable, if using the binding attribute. No conversion errors are thrown when using the EL variable with the value attribute, like that:
<h:inputText id="qty" value="#{qty}" converter="javax.faces.Number"/>
....
<h:commandButton value="Put into cart" type="submit"
action="#{shoppingCart.addToCart(product, qty)}"/>

Related

JSF input processing order

Is there a way to specify the order in which the inputs should be set after a submit?
Here is my case:
<h:inputText id="fieldA" value=#{myBean.myObject.fieldA}" />
<h:inputText id="fieldB" value=#{myBean.myObject.fieldB}" />
<p:autoComplete id="myObject" value=#{myBean.myObject" converter="myObjectConverter" />
<h:inputText id="fieldC" value=#{myBean.myObject.fieldD}" />
<h:inputText id="fieldD" value=#{myBean.myObject.fieldC}" />
The issue I am encountering is that, as the inputs are processed in the ordered they are declared, fieldA and fieldB are set in the initial instance of myObject, then myObject is set (with a new instance thus filedA and fieldB values are lost), and finally fieldC and fieldD are set with no problem.
If I could manage to start by setting myObject first, that would solve my problem.
I will temporarily set the fields and myObject into two different attributes of my bean, and populate myObject after clicking a save button. But it looks more like a hack than a real solution.
Needless to say that declaring the autocomplete before the inputtexts is not an option.
Thanks in advance.
In shortcut:
You can use <p:inputText> tag from primefaces. Then, you can disable all inputs. Add ajax to your autoComplete, and update other inputs after processing autoComplete. Inputs disable attribute can be set to depend on whether the autoComplete is not null. This way you will make the user to enter the autoComplet first.
you can try to set immediate="true" to p:autocomplete, so that it will be processed in the APPLY_REQUEST_VALUES phase, before all other components.
The simple solution is to update h:inputTexts when p:autocomplete item is selected to reflect its values:
<p:autoComplete id="myObject" value="#{myBean.myObject}" ...>
<p:ajax event="itemSelect" process="#this" update="fieldA fieldB fieldC fieldD" />
</p:autoComplete>
but this reverts user inputs on h:inputTexts. And since you can't move p:autocomplete on top, probably this is not acceptable too.
In case you can't/don't want to use ajax, you can force an early model update:
<p:autoComplete id="myObject" value="#{myBean.myObject}" immediate="true"
valueChangeListener="#{component.updateModel(facesContext)}" ... />
but, in my opinion, this is not very user friendly...
P.S. this time it's tested :)
There's no pretty way to get around this; your situation is already less than ideal and is hacky (re: not being able to simply reorder the fields). One workaround is for you to set fieldA and fieldB as attributes of myObject. In the converter, you could then pull the values off the components. Observe
Set attributes thus
<h:inputText id="fieldA" binding=#{fieldA}" />
<h:inputText id="fieldB" binding=#{fieldB}" />
<p:autoComplete id="myObject" value=#{myBean.myObject" converter="myObjectConverter">
<f:attribute name="fieldA" value="#{fieldA}"/>
<f:attribute name="fieldB" value="#{fieldB}"/>
</p:autoComplete>
The binding attribute effectively turns those components into page-scoped variables, allowing you to then pass them as attributes on your p:autocomplete
Get the values of those variables in your converter
//Retrieve the fields and cast to UIInput, necessary
//to retrieve the submitted values
UIInput fieldA = (UIInput) component.getAttributes().get("fieldA");
UIInput fieldB = (UIInput) component.getAttributes().get("fieldB");
//Retrieve the submitted values and do whatever you need to do
String valueA = fieldA.getSubmittedValue().toString();
String valueB = fieldB.getSubmittedValue().toString();
More importantly, why can't you just reorder the fields/logical flow of your form? You can avoid all this nasty business if you did

How to assign more than one parameter for one a4j:jsFunction?

Is there a way to declare more than one "assignTo" attribute to one a4j:jsFunction? Or can i set more than one value to one "assignTo" attribute of one a4j:jsFunction?
This for example:
<a4j:jsFunction name="newJsFunc" ajaxSingle="true" id="arrJsFunc">
<a4j:actionparam name="param1" assignTo="#{bean.value}" assignTo="#{bean.value}"
actionListener="#{bean.actionListenerMethod}" />
</a4j:jsFunction>
Use a4j:param inside a4j:jsFunction instead of a4j:actionparam. In assignTo you can assign value for only 1 bean property. See description of assignTo attribute in VDL doc:
EL expression for updatable bean property. This property will be updated if the parent command component performs an actionEvent.
You can include as many <a4j:param> tags as you need. See book Practical RichFaces Chapter 3 (Listing 3-20). Pseudocode:
<a4j:jsFunction>
<a4j:param name="param1" assignTo="#{someBean.value1}" />
<a4j:param name="param2" assignTo="#{someBean.value2}" />
<a4j:param name="param3" assignTo="#{someBean.value3}" />
</a4j:jsFunction>

JSF composite:attribute with f:attribute conversion error

I'm implementing a JSF component and need to conditionally add some attributes. This question is similar to a previous JSF: p:dataTable with f:attribute results in "argument type mismatch" error, but with a completely different error message, so I raised a new question.
<composite:interface>
<composite:attribute name="filter" required="false" default="false"
type="java.lang.Boolean"/>
<composite:attribute name="rows" required="false" default="15"
type="java.lang.Integer"/>
...
</composite:interface>
<composite:implementation>
<p:dataTable ivar="p" value="#{cc.attrs.dm}">
<c:if test="#{cc.attrs.filter}">
<f:attribute name="paginator" value="#{true}"/>
<f:attribute name="rows" value="#{cc.attrs.rows}"/>
</c:if>
...
<p:dataTable>
</composite:implementation>
This results in an error java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer. Even if I manually set this, I get errors:
<f:attribute name="rows" value="15"/> ... argument type mismatch
<f:attribute name="rows" value="#{15}"/> ... java.lang.Long cannot be cast
to java.lang.Integer
If I add the attribute directly, there is no exception and the correct number of rows is diplayed:
<p:dataTable var="p" value="#{cc.attrs.dm}" rows="#{cc.attrs.rows}">
This is indeed an unfortunate corner case with numbers in EL and composite component attributes. There's no solution for this. The type information is not available in #{cc.attrs} when used in <f:attribute> and thus treated as String. The #{15} cannot be represented as an integer in EL either, all numbers are always implicitly treated as Long when the type information is absent. The ClassCastException can be prevented by using a tag file instead of a composite component.
Your best bet is doing the check in the actual rows attribute itself.
<p:dataTable ... rows="#{cc.attrs.filter ? cc.attrs.rows : null}">

How to retrieve and show list of values in listbox and text corresponding to list item in textarea

I need to use a list box to show some values from database and do further processing when a single value from the list is selected.
At the PrimeFaces showcase site the example loads fixed (static) data into the listbox and there is one PrimeFaces command for each list item. How do I show items in a list box dynamically, when I may not know the number of items beforehand?
I also need to show some text corresponding to the item selected in list, in a textarea. Do I have to use an event listener for this purpose? I would like to leave the text area blank at the beginning. Only when a value is selected in the list box, then I want to use a bean to retrieve and store data using that textarea. Is this possible? How do I implement this?
How do I show items in a list box dynamically, when I may not know the number of items beforehand?
Use <f:selectItems> which you bind to a List<T> property. Basic example, assuming you're using EJB/JPA to interact with DB:
private Item selectedItem; // +getter+setter
private List<Item> availableItems; // +getter
#EJB
private ItemService service;
#PostConstruct
public void init() {
availableItems = service.list();
}
with
<p:selectOneListbox value="#{bean.selectedItem}" converter="itemConverter">
<f:selectItems value="#{bean.availableItems}" var="item"
itemValue="#{item}" itemLabel="#{item.someLabel}" />
</p:selectOneListbox>
The itemConverter should implement javax.faces.convert.Converter and convert from the Item object to its unique string representation (usually its DB identifier) in getAsString() and convert the other way round getAsObject().
I also need to show some text corresponding to the item selected in list, in a textarea. Do I have to use an event listener for this purpose?
Just put a <p:ajax> (the PrimeFaces equivalent of standard JSF <f:ajax>) in the listbox which updates the textarea. E.g.
<p:selectOneListbox value="#{bean.selectedItem}" converter="itemConverter">
<f:selectItems value="#{bean.availableItems}" var="item"
itemValue="#{item}" itemLabel="#{item.someLabel}" />
<p:ajax update="textarea" />
</p:selectOneListbox>
<p:inputTextarea id="textarea" value="#{bean.selectedItem.someText}" />
It'll be invoked when you select an item.
See also:
Our h:selectOneMenu wiki page - same applies to PrimeFaces p:selectOneListbox
Yes, for demonstration purposes most of the examples are loaded with static data. But if you look at the same example on PF showcase, the second listbox code is as follows:
<h:outputText value="Scrollbar: " />
<p:selectOneListbox id="scroll" value="#{autoCompleteBean.selectedPlayer1}"
converter="player" style="height:100px">
<f:selectItems value="#{autoCompleteBean.players}"
var="player" itemLabel="#{player.name}" itemValue="#{player}" />
</p:selectOneListbox>
and f:selectItems value attribute can point to a collection, an array, a map or a SelectItem instance. So coming to the above example players could be any list that is being populated using a database in the managed bean.
But if the instance is not a SelectItem, the labels are obtained by calling a toString on each object and finally the selected itemValue is set to the selectedPlayer1 attribute but you can also see that there is a converter in between so the incoming itemValue string is converted back to a player object and then set to selectedPlayer1.
And if you want to display the selected item in a text area, you can do something like this:
<h:outputText value="Scrollbar: " />
<p:selectOneListbox id="scroll" value="#{autoCompleteBean.selectedPlayer1}"
converter="player" style="height:100px">
<f:selectItems value="#{autoCompleteBean.players}"
var="player" itemLabel="#{player.name}" itemValue="#{player}" />
<p:ajax update="displayArea"/>
</p:selectOneListbox>
<p:inputTextarea id="displayArea" value="#{autoCompleteBean.selectedPlayer1}" />
Here the inputTextarea is updated using ajax with the value selected by the user.

How to save h:inputText values of a h:dataTable? My attempt only saves the value of last row

I'm having trouble making a dataTable where each row has a inputText and a commandLink. When the link is clicked, only it's row's inputText's data is submitted.
Something like this?
<h:dataTable value="#{bean.items}" var="item">
<h:column>
<h:inputText value="#{bean.value}"/>
</h:column>
<h:column>
<h:commandLink action="#{bean.save}" value="save">
<f:setPropertyActionListener target="#{bean.item}" value="#{item}" />
</h:commandLink>
</h:column>
</h:dataTable>
Bean:
#RequestScoped
public class Bean {
private Item item;
private String value;
Right now, as it is, it's using the last row's inputText to fill the value. I wrapped another h:form, but it broke other things and I've learned that nested h:form is not the right way to do it hehe
What's the correct way to do this?
Thanks.
You're binding the value of all HTML input elements to one and same bean property. This is of course not going to work if all those HTML input elements are inside the same form. All values are subsequently set on the very same property in the order as the inputs appeared in the form. That's why you end up with the last value. You'd like to move that form to inside the <h:column> (move; thus don't add/nest another one).
The usual approach, however, would be to just bind the input field to the iterated object.
<h:inputText value="#{item.value}"/>
An alternative, if you really need to have your form around the table, is to have a Map<K, V> as bean property where K represents the type of the unique identifier of the object behind #{item} and V represents the type of value. Let's assume that it's Long and String:
private Map<Long, String> transferredValues = new HashMap<Long, String>();
// +getter (no setter necessary)
with
<h:inputText ... value="#{bean.values[item.id]}" />
This way you can get it in the action method as follows:
String value = values.get(item.getId());
By the way, if you happen to target Servlet 3.0 containers which supports EL 2.2 (Tomcat 7, Glassfish 3, etc), then you can also just pass the #{req} as a method argument without the need for a <f:setPropertyActionListener>.
<h:commandLink ... action="#{bean.save(item)}" />
See also:
How and when should I load the model from database for h:dataTable
How can I pass selected row to commandLink inside dataTable?
How to dynamically add JSF components

Resources