I have an ajax request which outputs me a dataTable and form each row i also want to execute a button.Sadly no event gets invoked and i think it is because the second button is on a different level than the first search button.
JSF looks something like that:
<h:from>
<h:inputText id="search"
value="#{profileController.searchName}"/>
<h:commandButton value="Search by name"
action="#{profileController.searchProfileWithName(profileController.searchName)}">
<f:ajax execute="search"
render="output">
</f:ajax>
</h:commandButton>
<h:dataTable id="output"
value="#{profileController.searchResultList}"
var="p">
<h:column>
<f:facet name="header">Name</f:facet>
<h:outputText value="#{p.name}"/>
</h:column>
<h:column>
<f:facet name="header">Action</f:facet>
<h:commandButton value="Invite"
action="#{trainingController.inviteProfile(p)}">
<f:ajax/>
</h:commandButton>
</h:column>
</h:dataTable
</h:form>
JSF Managed Bean (requestScoped):
public String searchProfileWithName(String name) {
searchResultList = profileBean.findProfilesWithName(name);
return null;
}
ProfileBean (stateless):
public List<Profile> findProfilesWithName(String name) {
Query query = em.createNamedQuery("findProfilesWithName");
query.setParameter("name", "%" + name.replace(" ", "%") + "%");
return query.getResultList();
}
Anyone ideas in this?
The answer to this problem is the datasource. this is the link to the problem:
h:commandButton not working inside h:dataTable
Related
I have strange problem. I got a dataTable in which I present list of objects. Here's the code:
<h:dataTable value="#{XXXX.questions}" var="q" binding="#{varQ}" id="YYY">
<h:column>
<f:facet name="header">
header
</f:facet>
#{q.question}
</h:column>
<h:commandButton value="-" action="#{XXX.removeQuestion(varSurvey.index, varSec.index, varQ.rowIndex)}">
<f:ajax execute="#this" render="YYY"/>
</h:commandButton>
</h:column>
</h:dataTable>
As you can see - I got a button to remove one item from list. Method works fine, it removes element I want to be removed, but the datatable is not refreshed. I have no idea why.
My bean is SessionScoped, I got almost identical table in other part of my page, and it works which completely confuses me.
My bean method is like this :
public void removeQuestion(Integer surveyIndex, Integer sectionIndex, int questionIndex){
surveyList.get(surveyIndex).getSections().get(sectionIndex).getQuestions().remove(questionIndex);
}
so as you can see - it's almost basic example.
Here is code for my other table from same page:
<h:dataTable value="#{XXX.answers}" id="ZZZ" var="ans">
<h:column>
<h:inputText value="#{ans.choice}" styleClass="form-control">
<f:ajax event="change" execute="#this"/>
</h:inputText>
</h:column>
<f:facet name="footer">
<h:commandButton value="+" action="#{XXX.addMoreQuestions()}">
<f:ajax execute="#this" render="ZZZ"/>
</h:commandButton>
</f:facet>
</h:dataTable>
and method:
public void addMoreQuestions(){
answers.add(new Choice("question"));
}
And this works - when I click button, it adds one more question to list, and rerenders datatable with one more option.
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.
I have a datatable, and have links that allow the user to insert a row directly below the current row. This should then update the numbering.
It works perfectly once, creating a new row, populating the number and adding one to the numbering for all rows below.
If I click anything else though, it seems as though the ajax request completes but nothing happens.
You will see that I am using the #{table} variable to get the row index of the UIData element. I have tried using process="#form" and process="#this" in the commandLink, but to no avail sadly. Likewise, my method was returning void so I set it to return a null String, but the same result occurred.
XHTML
<h:form id="feForm">
<p:dataTable value="#{fichaExpandidaBean.feFlujoNormalList}" binding="#{table}" var="fn">
<p:column headerText="Paso:">
<h:outputText value="#{fn.orden}-"/>
</p:column>
<p:column headerText="Descripcion:">
<h:inputText value="#{fn.descripcion}" style="width:98%;"/>
</p:column>
<p:column headerText="Acciones">
<p:commandLink style="margin: 5px;" action="#{fichaExpandidaBean.agregarFilaFlujoNormal(table.rowIndex)}" update="#form">
<h:graphicImage title="Agregar fila abajo." value="/resources/imagenes/agregarFila.png" alt="AgregarFila"/>
</p:commandLink>
</p:column>
</p:dataTable>
</h:form>
Bean:
#Named(value = "fichaExpandidaBean")
#ConversationScoped
public class FichaExpandidaBean implements Serializable {
#Inject
private Conversation conversation;
...etc...
public String agregarFilaFlujoNormal(int row){
FeFlujonormal fn = new FeFlujonormal();
fn.setOrden(row + 2);
feFlujoNormalList.add(row + 1, fn);
for(int i = row + 2; i < feFlujoNormalList.size(); i++){
FeFlujonormal feTemp = feFlujoNormalList.get(i);
feTemp.setOrden(feTemp.getOrden()+1);
}
return null;
}
EDIT: I don't think it's a Primefaces issue, I get the same result with the following code:
<h:dataTable value="#{fichaExpandidaBean.feFlujoNormalList}" binding="#{table}" var="fn">
<h:column>
<f:facet name="header">Paso</f:facet>
<h:outputText value="#{fn.orden}-"/>
</h:column>
<h:column>
<f:facet name="header">Descripcion</f:facet>
<h:inputText value="#{fn.descripcion}" style="width:98%;"/>
</h:column>
<h:column>
<f:facet name="header">Acciones</f:facet>
<h:commandLink style="margin: 5px;" action="#{fichaExpandidaBean.agregarFilaFlujoNormal(table.rowIndex)}">
<f:ajax render="#form"/>
<h:graphicImage title="Agregar fila abajo." value="/resources/imagenes/agregarFila.png" alt="AgregarFila"/>
</h:commandLink>
</h:column>
</h:dataTable>
I have a dynamically expansible table with an add and remove button:
<h:form>
<h:dataTable id="tblFields" value="#{bean.fields}" var="field">
<h:column>
<h:inputText value="#{field.value}" />
</h:column>
<h:column>
<h:inputText value="#{field.value2}" />
</h:column>
<h:column>
<h:inputText value="#{field.value3}" />
</h:column>
<h:column>
<h:commandButton value="Remove">
<f:ajax listener="#{bean.onButtonRemoveFieldClick(field)}" immediate="true" render="#form" />
</h:commandButton>
</h:column>
</h:dataTable>
<h:commandButton value="Add">
<f:ajax listener="#{bean.onButtonAddFieldClick}" execute="#form" render="tblFields" />
</h:commandButton>
</h:form>
This is the associated backing bean:
#Named
#ViewScoped
public class Bean {
private List<Field> fields;
#PostConstruct
public void init() {
fields = new ArrayList();
fields.add(new Field());
}
public List<Field> getFields() {
return fields;
}
public void setFields(List<Field> fields) {
this.fields = fields;
}
public void onButtonRemoveFieldClick(Field field) {
fields.remove(field);
}
public void onButtonAddFieldClick() {
fields.add(new Field());
}
}
The use case is as follows:
Press the add button multiple times.
Fill out all values.
Press the remove button of one random row.
After that, all values filled so far disappears and show up blank. How can I keep them filled after pressing the remove button?
It's because you're in the remove button ajax-updating the entire form without processing the newly submitted input values. The immediate="true" on ajax listener skips the processing of all input components which do not have immediate="true" set. You need to remove the attribtue. The absence of execute attribute will cause only the current component (#this) to be processed by default. You need to explicitly specify #form.
So, just do the same as in your add button. Replace immediate="true" by execute="#form".
<f:ajax listener="#{bean.onButtonRemoveFieldClick(field)}" execute="#form" render="#form" />
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.