On complex data input forms it may happen that one needs to edit a form in a form. As this is not possible in JSF2, I wonder what better solution could be found for this problem. Here's an example of what I need:
given: two beans: OuterBean and HobbyBean; a list of HobbyBeans is used in OuterBean
OuterBean is a ManagedBean (in SessionScope)
HobbyBean contains two fields hobby and like
I want to add HobbyBeans on the form of adding a user's name in OuterBean without submitting OuterBean but submitting new values to fill the list. Here's the code example:
<!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:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html">
<h:head>
</h:head>
<h:body>
<h:form>
<h:panelGrid columns="2">
<h:outputText value="Name" />
<h:inputText value="#{outerBean.name}" required="true" />
<h:outputText value="Hobbies" />
<h:dataTable id="ht" value="#{outerBean.hobbies}" var="h">
<h:column>
<h:outputText value="#{h.hobby}" />
<f:facet name="footer">
<h:inputText value="#{outerBean.hobby}" required="true" />
</f:facet>
</h:column>
<h:column>
<h:outputText value="#{h.like}" />
<f:facet name="footer">
<h:inputText value="#{outerBean.like}" required="true" />
<h:commandButton action="#{outerBean.addHobby}" value="+" immediate="true">
<f:ajax render="ht" />
</h:commandButton>
</f:facet>
</h:column>
</h:dataTable>
</h:panelGrid>
</h:form>
</h:body>
</html>
Yes, there is no command button for the outer form, but that's not the question here. The commandButton is for the inner form and therefore set attribute immediate = true. Doing this, all fields are NOT checked to be not empty (required-Tag is ignored). But also is the content of this fields ignored and not set into the ajax request. How do I avoid this and send the field values of h.hobby and h.like within the ajax request to the OuterBean?
Here the beans:
#ManagedBean
#SessionScoped
public class OuterBean
{
private List<HobbyBean> hobbies;
private String name;
private String hobby;
private Integer like;
public OuterBean()
{
hobbies = new ArrayList<HobbyBean>();
}
public String addHobby()
{
hobbies.add(new HobbyBean(hobby, like));
System.out.println("hobbies: " + hobbies.toString());
return "";
}
public String submit()
{
System.out.println("name is " + name);
return "";
}
// + getter & setter
}
/* ------------------------------------------------------------------------ */
public class HobbyBean
{
private String hobby;
private Integer like;
public HobbyBean(String hobby, Integer like)
{
this.hobby = hobby;
this.like = like;
}
public String toString()
{
return hobby == null ? "" : hobby.concat(",").concat(like == null ? "" : like.toString());
}
// + getter & setter
}
Now what happens when I add a hobby to the bean is that there is no hobby added because the bean fields hobby and like are not set (the list is empty, log is: "hobbies: []"). How can I make it work?
Well your hobbies is empty because you don't tell the f:ajax what to submit. IF you want to do a partial submit (i guess that's what you want) You can try the following:
<h:form>
<h:panelGrid columns="2">
<h:outputText value="Name" />
<h:inputText value="#{outerBean.name}" required="true" />
<h:outputText value="Hobbies" />
<h:dataTable id="ht" value="#{outerBean.hobbies}" var="h">
<h:column>
<h:outputText value="#{h.hobby}" />
<f:facet name="footer">
<h:inputText id="hobby" value="#{outerBean.hobby}" required="true" />
</f:facet>
</h:column>
<h:column>
<h:outputText value="#{h.like}" />
<f:facet name="footer">
<h:inputText id="like" value="#{outerBean.like}" required="true" />
<h:commandButton action="#{outerBean.addHobby()}" value="+" >
<f:ajax execute="hobby like" render="ht" />
</h:commandButton>
</f:facet>
</h:column>
</h:dataTable>
</h:panelGrid>
</h:form>
As you can see in the code you tell f:ajax wich part of the form needs to be submitted when you push the button. If you check your bean now you will see that only the hobby and like are added to the bean. The name part will not be submitted. You say all fields are not checked. This is because you use immediate=true this skips validation. I would suggest not to use it. Look here for more information about immediate= true http://balusc.blogspot.nl/2006/09/debug-jsf-lifecycle.html#WhenShouldIUseTheImmediateAttribute Hopes this help you.
Related
I’m trying to use ajax in jsf.
So, I have inputtextarea and datatable:
<h:form>
<h:inputTextarea id="mailstextarea" style="width:100%" value="#{newMembersBean.newMembersStr}">
<f:ajax event="keyup" render="newmembertable" execute="mailstextarea" />
</h:inputTextarea>
<h:dataTable id="newmembertable" styleClass="tableWidth" value="#{newMembersBean.newMembers}" var="member">
<h:column>
<f:facet name="header">#{msgs.name}</f:facet>
#{member.name}
</h:column>
<h:column>
<f:facet name="header">#{msgs.surename}</f:facet>
#{member.sureName}
</h:column>
<h:column>
<f:facet name="header">#{msgs.email}</f:facet>
#{member.email}
</h:column>
<h:column>
<f:facet name="header">#{msgs.phone}</f:facet>
#{member.phone}
</h:column>
</h:dataTable>
<h:commandButton type="submit" value="#{msgs.add}"/>
</h:form>
I want to change newMembersBean.newMembers List (and datatable newmembertable) on every value change in textarea…
In my bean I’m trying to do somethink like this (now only for testing, I want to show all users, if user have typed more then 3 characters):
#Named
#ConversationScoped
public class NewMembersBean implements Serializable {
private List<UsersEntity> newMembers = new ArrayList<UsersEntity>();
private String newMembersStr = "";
......
public List<UsersEntity> getNewMembers() {
UsersDao ud = new UsersDao();
if(newMembersStr.length() > 3)
{
newMembers = ud.getAllUsers();
}
return newMembers;
}
.....
}
But when I’m typing text in textare nothing happens.
Please help.
Thanks.
When using ajax inside a composite component, the ajax feature isn't working. What's wrong with the code?
the composite component:
<composite:interface>
<composite:attribute name="filter" required="true" type="java.lang.String" />
<composite:attribute name="list" required="true" type="java.util.List" />
</composite:interface>
<composite:implementation>
<h:inputText value="#{cc.attrs.filter}">
<f:ajax event="keyup" render="#{cc.clientId}:table#{cc.clientId}" />
</h:inputText>
<h:dataTable id="table#{cc.clientId}" value="#{cc.attrs.list}" var="elem">
<h:column>
<h:outputText value="#{elem}" />
</h:column>
</h:dataTable>
</composite:implementation>
now the bean
#ManagedBean
#SessionScoped
public class Ajaxcc
{
private String filter;
private List<String> list;
public Ajaxcc()
{
list = new ArrayList<String>();
list.add("one");
list.add("two");
list.add("three");
list.add("four");
}
public List<String> getList()
{
List<String> filteredList = new ArrayList<String>();
for (String s : list)
{
if (filter == null || filter.trim().equals(""))
{
filteredList.add(s);
}
else if (s.contains(filter))
{
filteredList.add(s);
}
}
return filteredList;
}
public String getFilter()
{
return filter;
}
public void setFilter(String filter)
{
this.filter = filter;
}
}
now the view:
<h:form>
<myCustomComponent:ajaxcc list="#{ajaxcc.list}" filter="#{ajaxcc.filter}" />
</h:form>
I'm using myfaces 2.1.10, deploying on a tomcat 7.0.39 by maven.
Expected behaviour: the list on the web site should be reduced to one, two and four whenever I press the o - button
Failure: the list isn't reduced.
What could be the solution?
BTW, if I put the content of the composite component into the view, it works correctly:
<h:form>
<h:inputText value="#{ajaxcc.filter}">
<f:ajax event="keyup" render="table" />
</h:inputText>
<h:dataTable id="table" value="#{ajaxcc.list}" var="elem">
<h:column>
<h:outputText value="#{elem}" />
</h:column>
</h:dataTable>
</h:form>
In this case pressing o reduces the list to the expected values. Besides, I found out that the response of the composite component ajax call seems to be "empty" for the data table field values; the response of the direct ajax call contains the new list.
<h:inputText ...>
<f:ajax ...render="#{cc.clientId}:table#{cc.clientId}" />
</h:inputText>
<h:dataTable id="table#{cc.clientId}" ...>
This is unnecessarily clumsy. Both components are in the same naming container (the composite itself!), so the prefix is implicitly already done by the composite itself. The suffix is valid, but just unnecessary. The composite component's own ID already enforces the uniqueness in the context of its parent naming container component. Opening the page in browser, rightclick-view source and observing the IDs in generated HTML output should already have given insights about that.
Just keep it simple:
<h:inputText ...>
<f:ajax ...render="table" />
</h:inputText>
<h:dataTable id="table" ...>
See also:
How to find out client ID of component for ajax update/render? Cannot find component with expression "foo" referenced from "bar"
Is it possible to update non-JSF components (plain HTML) with JSF ajax?
I have a JSF view that lists items in a collection in a Primefaces DataTable. The rightmost columns contain remove buttons. When a remove button is clicked, it is supposed to make an Ajax call, remove the corresponding item from the session variable Cart and update the view in-place. I would like the request and the view change to be as minimal as possible.
Here is what I have for this purpose:
<!DOCTYPE html>
<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:p="http://primefaces.org/ui">
<h:head>
<title>Register user</title>
</h:head>
<h:body>
<f:view>
<h:form id="itemsForm">
<p:outputPanel id="items">
<p:dataTable value="#{cart.itemList}" var="item">
<p:column>
<f:facet name="header">
<h:outputText value="name" />
</f:facet>
<h:outputText value="#{item.product.description}" />
</p:column>
<p:column>
<f:facet name="header">
<h:outputText value="quantity" />
</f:facet>
<h:outputText value="#{item.quantity}" />
</p:column>
<p:column>
<f:facet name="header">
<h:outputText value="" />
</f:facet>
<p:commandButton icon="ui-icon-close" title="remove from cart">
<p:ajax listener="#{cart.removeItem}"
update="form:itemsForm"
process="#this" />
</p:commandButton>
</p:column>
<f:facet name="footer">
Total amount: ${cart.totalAmount}
</f:facet>
</p:dataTable>
</p:outputPanel>
</h:form>
</f:view>
</h:body>
</html>
Accordingly, I have the following method in Cart.java
public void removeItem() {
System.out.println("REMOVE REQUEST ARRIVED");
}
However, the removeItem method isn't even executing when I click a remove button.
So my questions are:
1) What is wrong with my Ajax call? What changes should I make to my XHTML?
2) How do I handle the request in the removeItem method and return a response?
3) How do I update the footer, which displays the totalAmount?
You can pass #{item} as a parameter of your method call in the actionListener.
Your .xhtml page should look like this:
<p:dataTable id="cartTable" value="#{cart.itemList}" var="item">
<p:column>
<f:facet name="header">
<h:outputText value="" />
</f:facet>
<p:commandButton icon="ui-icon-close" title="remove from cart"
actionListener="#{cart.removeItem(item)}" update="cartTable" />
</p:column>
</p:dataTable>
And this is the method removeItem of your ManagedBean:
#ManagedBean
#ViewScoped
public class Cart {
private List<Item> itemList;
public void removeItem(Item item) {
itemList.remove(item);
}
}
1) <p:commandButton uses ajax by default , so instead placing the p:ajax use the action or actionListener of the <p:commandButton
2) I would use the action of the button and return null
3) update="#form" should update the entire form and this will update the entire table
here an example of a working button (link) from my page , i used the f:setPropertyActionListener to "pass" some data to the delete method
<p:commandButton action="#{cart.removeItem}" icon="ui-icon-close" title="remove from cart" update="#form" process="#this" >
<f:setPropertyActionListener
target="#{cart.selectedItem}"
value="#{item}" />
</p:commandButton>
in your class add this
private Item selectedItem;
public Item getSelectedItem() {
return selectedItem;
}
public void setSelectedItem(Item selectedItem) {
this.selectedItem = selectedItem;
}
i have a SEAM 2 application and i have a strange situation. I'm developing with Eclipse Indigo, and i need to create a page with a grid where each row has a button that display a popup window with a list and you can choose one item of the list with a link and the value selected is shown in the row.
So i have this component:
#Name("paramContHome")
#Scope(ScopeType.CONVERSATION)
public class ParamContHome extends KubeDAO<ParametroSistema>{
private static final long serialVersionUID = 1L;
#In
private LoginUser loginUser;
#In(required=false,create=true)
private CuentaContHome cuentaContHome;
public void load(){
try{
setInstance(getEntityManager().find(ParametroSistema.class, prctId));
}catch (Exception e) {
clearInstance();
setInstance(new ParametroSistema());
}
}
public void selCuentaParam(ParametroSistema par) {
setSelParam(par);
cuentaContHome.getCuentasList();
}
public void setCuentaParam(CuentaContable cta) {
selParam.setValorNum(cta.getId().floatValue());
selParam.setSelObj(cta);
}
...
}
That contains the methods that i'm trying to call from xhtml page. This is the xhtml page:
<?xml version="1.0" encoding="iso-8859-1" ?>
<!DOCTYPE composition 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:s="http://jboss.com/products/seam/taglib"
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:a="http://richfaces.org/a4j"
xmlns:rich="http://richfaces.org/rich"
xmlns:p="http://primefaces.prime.com.tr/ui"
template="/layout/templateKu.xhtml">
<ui:define name="body">
<rich:panel>
<f:facet name="header">#{app.paramact_head}</f:facet>
<rich:spacer height="20" />
<h:form id="formA">
<p:growl globalOnly="true" sticky="false" life="3000" />
<p:focus />
<a:queue name="q1" />
<rich:dataTable var="res" value="#{paramContHome.resultList}"
rendered="#{not empty paramContHome.resultList}" rows="10"
align="center" rowClasses="tableInfo1 tableInfo2"
headerClass="tablaHeader" footerClass="tableScroll">
<f:facet name="header">#{app.paramact_list}</f:facet>
<rich:column filterBy="#{res.nombre}" filterEvent="onkeyup">
<f:facet name="header">#{app.paramact_nombre}</f:facet>
<h:outputText value="#{res.nombre}" />
</rich:column>
<rich:column>
<f:facet name="header">#{app.transferencia_valornum}</f:facet>
<h:inputText value="#{res.selObj.nombre}" size="20" >
<a:support event="onblur" ajaxSingle="true" eventsQueue="q1" reRender="_table"/>
</h:inputText>
<a:commandButton ajaxSingle="true"
action="#{paramContHome.selCuentaParam(res)}" reRender="sCta"
onclick="#{rich:component('selCta')}.show();"
styleClass="modifyBtn" value=" " style="width:30px;">
</a:commandButton>
</rich:column>
<f:facet name="footer">
<rich:datascroller id="ds1" renderIfSinglePage="true" />
</f:facet>
</rich:dataTable>
</h:form>
</rich:panel>
<rich:modalPanel id="selCta" width="400" moveable="false" autosized="true" top="50px"
onbeforeshow="activeModal.setActiveModalPanel('selCta');">
<f:facet name="header">#{app.general_lov}</f:facet>
<f:facet name="controls">
<h:panelGroup>
<h:graphicImage value="/kubeImg/close.png" styleClass="closeBtn"
onclick="#{rich:component('selCta')}.hide();" />
</h:panelGroup>
</f:facet>
<s:div id="sCta"><ui:include src="selCta.xhtml" /></s:div>
</rich:modalPanel>
</ui:define>
</ui:composition>
This is the button where i wanna call the method selCuentaParam of component paramContHome:
<rich:column>
<f:facet name="header">#{app.transferencia_valornum}</f:facet>
<h:inputText value="#{res.selObj.nombre}" size="20" >
<a:support event="onblur" ajaxSingle="true" eventsQueue="q1" reRender="_table"/>
</h:inputText>
<a:commandButton ajaxSingle="true"
action="#{paramContHome.selCuentaParam(res)}" reRender="sCta"
onclick="#{rich:component('selCta')}.show();"
styleClass="modifyBtn" value=" " style="width:30px;">
</a:commandButton>
</rich:column>
Inside this method, i call a method from another component, cuentaContHome:
#In(required=false,create=true)
private CuentaContHome cuentaContHome;
...
public void selCuentaParam(ParametroSistema par) {
setSelParam(par);
cuentaContHome.getCuentasList();
}
But when i run the application and enter to the page, and i press the button, it doesn't calle the method selCuentaParam. I've checked this because i put breakpoints inside it and put System.out.println and doesn't invoke it. Do you know why this happens, is something related to component initialization?
Regards.
Well, i found the problem, i think. In my screens i follow a certain pattern: First i have a xhtml where i show a grid of database records with a button to go to a second xhtml wich has a form to create a new record. This button begins a conversation, so in the xhtml that has a form (i call it detail.xhtml) it begins the conversation or joins to existing one. So, i modified the pages.xml of the first xhtml (i call it list.xhtml) in the next way:
<?xml version="1.0" encoding="UTF-8"?>
<page xmlns="http://jboss.com/products/seam/pages"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jboss.com/products/seam/pages http://jboss.com/products/seam/pages-2.2.xsd">
<action execute="#{paramContHome.getParametrosContables()}" on-postback="false"/>
<begin-conversation propagation="begin" join="true" />
</page>
I used first just <begin-conversation /> and but it gives me this exception begin() called from long-running conversation, try join=true so i added this to begin-conversation and it works!!
I need to output the text that is selected in the selectOneMenu-list. My code is as follows;
<h:selectOneMenu value="#{DataForm.stationed}" id="globalFilter" onchange="carsTable.filter()" style="width:350px;font-size:13px;" >
<f:selectItems value="#{DataForm.listHotel}" var="user" itemValue="#{user[1]}" itemDisabled="false" itemLabel="#{user[1]}" />
<h:outputText value="#{carsTable[1]}" style="width:350px"/>
</h:selectOneMenu>
How do I code this?
EDIT
This Listbox is within a <datatable>
<h:body>
<h:form id="form1" >
<p:dataTable var="car" value="#{DataForm.listHotels}" widgetVar="carsTable" paginator="true" rows="10" onRowSelectComplete="carDialog.show()" emptyMessage="No hospital found with given criteria" selectionMode="single" onRowSelectUpdate="growl" style="width:1400px;font-size:13px;">
<h:selectOneMenu value="#{DataForm.stationed}" id="globalFilter" onchange="carsTable.filter()" style="width:350px;font-size:13px;" >
<f:selectItems value="#{DataForm.listHotel}" var="user" itemValue="#{user[1]}" itemDisabled="false" itemLabel="#{user[1]}" />
<h:outputText value="#{carsTable[1]}" style="width:350px"/>
</h:selectOneMenu>
</p:dataTable>
<f:ajax render= "#form1" >
<h:selectOneMenu value="#{DataForm.stationed}">
<f:selectItems value="#{DataForm.listHotels}" var="item" itemValue="#{DataForm.listHotels}" itemLabel="#{DataForm.listHotels}" />
</h:selectOneMenu>
</f:ajax>
</h:form>
</h:body>
I think you should remove the nested <h:outputText/> first, it doesn't really make sense at that position. Also, from your question and example code, it doesn't really become clear what PrimeFaces has to do with it.
To output the selected value, simply print the expression #{DataForm.stationed}, since this is the binding that will receive the selected value.
The following example demonstrates this via AJAX, but it would work the same way if you used an action and a regular form submit.
Facelet
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core">
<h:head />
<h:body>
<h:form id="form">
<f:ajax render="form">
<h:selectOneMenu value="#{selectOneMenuBean.value}">
<f:selectItems value="#{selectOneMenuBean.items}" var="item" itemValue="#{item}" itemLabel="#{item}" />
</h:selectOneMenu>
</f:ajax>
Selected value: #{selectOneMenuBean.value}
</h:form>
</h:body>
</html>
Bean
#ViewScoped
#ManagedBean
public class SelectOneMenuBean {
private List<String> items = Arrays.asList("a", "b", "c");
private String value;
public List<String> getItems() {
return items;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
p.s.
In your code example the EL names for your beans start with a capital. This is a little against the typical conventions. Also, you might want to pay some attention to your names and types. The bean returns something called listHotel, but this is assigned to a variable named user, which is then indexed by an integer. I would recommend aligning names (e.g. collection name = users, variable name user) and using properties instead of indexes (e.g. user.name).