How to prepopulate repeating h:selectOneMenu? - java

Modifying working form with one spot per order to multiple spots per order I met problems with prepopulating h:selectOneMenu. Exception is java.lang.IllegalArgumentException: Value binding '#{spot.deliveryTypes}'of UISelectItems with component-path {Component-Path : [Class: javax.faces.component.UIViewRoot,ViewId: /order.jsp][Class: javax.faces.component.html.HtmlForm,Id: pf][Class: javax.faces.component.html.HtmlSelectOneMenu,Id: _idJsp11][Class: javax.faces.component.UISelectItems,Id: _idJsp12]} does not reference an Object of type SelectItem, SelectItem[], Collection or Map but of type : null
old working JSP code:
<h:selectOneMenu value="#{order.deliveryType}" immediate="true">
<f:selectItems value="#{order.deliveryTypes}" />
</h:selectOneMenu>
new not working JSP code:
<c:forEach var="spot" items="${order.spots}">
<h:selectOneMenu value="#{spot.deliveryType}" immediate="true">
<f:selectItems value="#{spot.deliveryTypes}" /> <%-- Works as empty list if this line removed --%>
</h:selectOneMenu> <c:out value="${spot.name}"/><br/>
</c:forEach>
New field was introduced List<Spot> spots as well as getter and setter. List<SelectItem> getDeliveryTypes() has been moved from managed bean class Order to class Spot.
How to access to spot.deliveryTypes? Changing # to $ didn't help because value= doesn't accept EL.
MyFaces 1.1.8
Thanks.

JSTL and JSF doesn't go nicely hand in hand. The JSP won't be processed from top to bottom as you'd expect from the coding. It's more so that JSTL processes the JSP from top to bottom first and then hands the generated result over to JSF for its own processing from top to bottom. This makes especially the c:forEach unusable for this kind of requirements. In this particular case, the ${spot} won't be there anymore when it's JSF's turn to process the JSP page.
You'd like to use a JSF UIData based component instead of c:forEach. A fullworthy JSF alternative to the c:forEach is Tomahawk's t:dataList. Use it and your problem will be solved.
If it happens that you're using Facelets instead of JSP, you can also use its ui:repeat instead.

Related

JSF Pass OutputText and InputText value to a property

This is my second day working with JSF. Have no previous background in Java , Have Been working with Flex and C++ for quite some time. Some history so that everybody knows where im coming from . For a "rush" project i am running into an issue
<h:panelGroup id="txeTab" layout="block" class="txeTab">
<h1>TXE</h1>
<h:form id="txeForm">
<h:panelGrid columns="3">
<c:forEach items="${txeConfBean.getListTable()}" var="property">
<h:outputLabel id="key" value="${property.key}"/>
<h:inputText id="value" value="${property.value}" />
<h:commandButton value="Change" action='${txeConfBean.setProperty('key','value')}'/>
</c:forEach>
</h:panelGrid>
</h:form>
</h:panelGroup>
and The Bean is as follows
public HashMap <String,String> getListTable ()
{
String[] keys = new String[super.keyData.size()];
HashMap <String,String> retKeys = new HashMap <String, String>();
super.keyData.toArray(keys);
for (int i=0;i<keys.length;i++)
{
if(!keys[i].isEmpty())
{
retKeys.put(keys[i],getProperty(keys[i]));
}
}
return retKeys;
}
im able to display the Key,value pairs recursively. But i want to update a specific key with new value once someone updated the h:inputText id="value" value="${property.value}" /> and press the command button the new value is written to. Need help in this regard . Googling it make me feel there are too many ways to do it. Need help. I am just unable to figure out what to pass to ${txeConfBean.setProperty('key','value')} How can i pass the value of both InputText and OutPutText to setProperty ?
The ${}, which is inherited from legacy JSP, can't do a "set" operation on a property. It can only do a "get" operation on the property.
If you want to support both "get" and "set" on a property, you need the #{}. Even more, in general in JSF, you should not use ${} anymore. Further, in order to get/set a map value by an input component, you have to reference the map value by its key using the brace notation as #{bean.map[key]}.
<h:form id="txeForm">
<h:panelGrid columns="3">
<c:forEach items="#{txeConfBean.listTable}" var="property">
<h:outputLabel id="key" value="#{property.key}"/>
<h:inputText id="value" value="#{txeConfBean.listTable[property.key]}" />
<h:commandButton value="Change" />
</c:forEach>
</h:panelGrid>
</h:form>
Note that the command button action is omitted. JSF/EL will "automagically" already call the map's put() method when the model value is about to be updated. It's unnecessary in this particular construct. Also note that in this construct, the entire form is submitted. You might want either to put the command button outside the table, or to use <f:ajax> to submit the current "row" only.
See also:
Difference between JSP EL, JSF EL and Unified EL
Unrelated to the concrete problem: you're doing the business job in a getter method. This is extremely inefficient in case the property is referenced in iterating components. Do the business job in (post)constructor instead. It'll be invoked only once. This way you can make the getter really a fullworthy getter.
public HashMap<String,String> getListTable() {
return listTable;
}
See also:
JSF calling setter & getter multiple times.

Make JSF 2.0 execute methods as they are assigned to params, not store reference to method?

Before I begin, my apologies if the wording of this question's title is confusing. I hope my explanation here will make it much clearer.
In a JSF template of my application, I want to include another template and pass a parameter to it that holds the results of an application method. In this parent template, I have:
<ui:repeat var="loopObject" value="#{ApplicationBean.objectList}">
<ui:include src="anotherTemplate.xhtml">
<ui:param name="firstParam"
value="#{ApplicationBean.initForOtherTemplate(loopObject)}" />
</ui:include>
</ui:repeat>
It turns out, though, that initForOtherTemplate is not executed at this point and firstParam contains a reference to that method, rather than its return value, as I expected.
Actually, while initForOtherTemplate does have a return value, anotherTemplate.xhtml doesn't need it. However,the method does set up some other objects in ApplicationBean that this new template will use. For example, it sets values for importantInfo and importantInfoToo, which the other template needs.
anotherTemplate.xhtml contains:
<ui:remove>
<!--
When a parameter contains a method call, the method isn't executed until
the parameter is referenced. So we reference the parameter here and ignore
the results. There must be a better way.
-->
</ui:remove>
<h:outputText value="#{firstParam}" style="display: none;" />
<h:outputText value="#{ApplicationBean.importantInfo}" />
<h:outputText value="#{ApplicationBean.importantInfoToo}" />
If this template didn't reference firstParam, then importantInfo and importantInfoToo wouldn't be set or have unpredictable values. This is very disappointing, because I expected initForOtherTemplate to be executed in the parent template, rather than here, which feels messy.
How can I get the assignment of the parameter to actually execute the method immediately rather than store a reference to it?
The <ui:repeat> is an UIComponent which runs during view render time. The <ui:include> is a TagHandler (like JSTL) which runs during view build time. So at the moment <ui:include> runs, the <ui:repeat> isn't running and thus the #{loopObject} isn't available in the EL scope at all.
Replacing <ui:repeat> by <c:forEach> should solve this particular problem.
<c:forEach var="loopObject" items="#{ApplicationBean.objectList}">
<ui:include src="anotherTemplate.xhtml">
<ui:param name="firstParam"
value="#{ApplicationBean.initForOtherTemplate(loopObject)}" />
</ui:include>
</c:forEach>
See also:
JSTL in JSF2 Facelets... makes sense? - Substitute "JSTL" with "ui:include".

How can I populate data in JSF [duplicate]

This question already has answers here:
How to populate options of h:selectOneMenu from database?
(5 answers)
Closed 6 years ago.
Up until now, I have always been using JSP to display pages. When a user request for a page such as "Add Item", I will load all Item Category in an Array List and display them as options in select box like this:
<select name="category>
<%
ArrayList<Category> categories = (ArrayList<Category>) request.getAttribute("categories");
for (Category c : data) {
%>
<option value="<%= c.getId() %>"><%= c.getName() %></option>
<%
}
%>
</select>
From the book "JavaServer Faces 2.0, The Complete Reference", I learnt that: "JSF enforces clean Model-View-Controller separation by disallowing the inclusion of Java code in markup pages". Hence, I'd be very grateful if someone could show me how I can handle the above task using JSF since I cannot use Java code as I have always done anymore.
Best regards,
James Tran
JSF 2.0 uses Facelets as the templating method, which in a nutshell is XHTML with some additional elements.
While technically you can perform method calls from Facelets, in general the idea is to access a JavaBean with proper geter/setter methods to perform your data moving. You can accomplish this as the below segment of code shows:
<h:selectOneMenu value="#{backingBean.selectedCategory}">
<f:selectItems value="#{backingBean.categoryList}"/>
</h:selectOneMenu>
On the bean side of things, you want to expose a bean to JSF using either faces-config (which is largely discouraged) or a mechanism such as CDI or the Managed Bean infrastructure. I highly recommend you look into using SEAM if you go the CDI route, as it will unify the (currently really strangely disparate) Managed Bean and CDI frameworks, so you can use JSF scopes in CDI, and have CDI beans available in JSF scopes.
#ManagedBean(name="backingBean")
#ViewScoped
public class MyJavaBackingBean {
#ManagedProperty("#{param.categories}")
protected List<String> categoryList
public void setSelectedCategory(String value) {
this.selectedCategory = value;
}
public String getSelectedCategory() {
return this.property;
}
...
}
You can also make the getters do lazy initialization of your values (for pulling categoryList from a database for example), and use some other JSF annotations to do various initialization tasks.
You can also code action methods which return a String representing the JSF action (this gets coded into your faces-context.xml file) to take after returning. Phase listeners on the backing bean can also be called at various stages of page rendering, validation and submission, getting you very fine grained control.
categoryList in the above example is not limited to basic types of course, and <f:selectItems> also has some syntax for writing out the textual version of your select items, so you can make some quite complex expressions to display each item in a friendly way.
Create a bean and make it known with e.g. #Named so you can refer to it from your JSF script. Then give that bean a method returning the data you want to show, and invoke that method from your JSF script in a location where that data is expected e.g. a loop construct.
Store the data you want to display in a Java list, and expose that list as a property of a backing bean. The use the appropriate JSF tag to display that property.
In JSF 2.0 you can include the tag h:selectOneMenu in which you get the value where you store the item value selected. The value in f:selectItems could be a collection of any object the most of times SelectItem in this object your declare value object and the label to display.
<h:selectOneMenu value="#{backingBean.selectedvalue}">
<f:selectItems value="#{backingBean.List}"/> </h:selectOneMenu>
if you required values and labels of another object in you must declare
<h:selectOneMenu value="#{backingBean.selectedvalue}">
<f:selectItems value="#{backingBean.ListCar}" var="car" itemLabel="#{car.model}" itemValue="#{car.modelId}"/>
</h:selectOneMenu>

returning a4j:included content using bean-generated rich:dropDownMenu

I may be missing a couple of points, but I've hacked together a jsf/richfaces app and want to be able to do the simplest ajax-based nav:
main page contains ref to my backing bean's menu
<h:form>
<rich:dropDownMenu binding="#{PrismBacking.nodeMenu}" />
</h:form>
this refers to the code for the backing bean methods
this is my main page ajax panel
<rich:panel id="content">
<a4j:include viewId="#{PrismBacking.viewId}" />
</rich:panel>
i can't work out how to get the backing bean to use the selected item from the rich:dropDownMenu to update that which is returned by getViewId.
i guess:
1) i need to ensure the menu items in the getNodeMenu method have the right payload so setViewId is called with the correct String and my rich:panel id="content" is reRendered.
any pointers as to how to do this would be greatly appreciated.
mark
You are not setting the reRender attribute anywhere in your code (in the menu items) so the panel is not going to be updated after you select an item from the dropdown.
You also have to set the ajaxSubmit attribute en each menuItem to true in order to execute an ajax request. Also check that your listener is executed.
Take a look at the example http://livedemo.exadel.com/richfaces-demo/richfaces/dropDownMenu.jsf?c=dropDownMenu . You can download the code if you want from the richfaces site.
Using binding should be avoided if possible. Take a look at the RichFaces demo - there are source codes for each example, and see how it is achieved.
(This doesn't answer your question, and for better :) )

Passing data from request ManagedBeans in JSF

I'm somewhat confused about the lifecycle of ManagedBeans of type "request".
In this example i'm using one request bean "userBean" to fill this page and one request bean "userEditBean" to fill the following edit page.
<h:form>
<h:panelGrid border="1" columns="2">
<h:outputText value="Name" />
<h:outputText value="#{userBean.user.name}" />
...
</h:panelGrid>
<h:commandButton value="Edit" action="edit" actionListener="#{userEditBean.init}">
<f:attribute name="user" value="#{userBean.user}"/>
</h:commandButton>
</h:form>
When i press the Edit button a userEditBean is created but the attribute map resolves "user" to null.
Does this mean that the attribute EL is resolved after the userBean has already been destroyed? How can i pass values from incoming beans to outgoing beans?
You're setting the attribute value with an expression, not a static value. Whenever you request the value, the expression will be re-evaluated again. The userBean.user apparently isn't present in the subsequent request. You need to ensure that it is there (in other words, the constructor of the userBean should ensure that the user is been created and set.
There are however alternatives. One of the best is to use Tomahawk's <t:saveState> for that. Add it somewhere in the page:
<t:saveState value="#{userBean.user}" />
That said, I agree with Bozho that the whole approach is a bit strange, but that's another story. You may however get lot of useful ideas out either of the following articles: Communication in JSF and/or Using Datatables. Good luck.
request scope means the bean lives during one request. And you fill your edit page (1st request), and send the edited user (2nd request).
In addition to that, <f:attribute> sets tha attributes in the parent component, not in the request. So in your code the attributes will be found in the button.getAttributes() (if you have bound your button).
Furthermore, it is strange to have an actionListener method named init. Since you don't need the event, you can set the action to be the method which will do the editing operation, and make that method return the navigation-rule you want.

Categories

Resources