Dynamic input fields (values) reset on remove item/field - ajax

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" />

Related

f:ajax firing only once

I have a a form loading a list from my database. I can update, and delete the row i select and that is working fine. Now I added a start and stop button to each row to enable start an engine from another application. Now what I want to do is when i click on start ,my engine would start based on that row and that row would hide the start button and show the stop button.
I have implemented ajax on those columns in the row but it updates all rows at once and the ajax only triggers once.
What am I doing wrong here and can you show me the best way to press on start and then hide my start-button and show my stop-button or press on stop and hide my stop-button and show my start-button on that particular row.
snippet of codes in my managedbean
#ManagedBean
#SessionScoped
public class HibernateController {
private ArrayList<IPAddress> ipAddresses;
private Logger logger = Logger.getLogger(getClass().getName());
private boolean isStarted = false;
private boolean isStopped = true;
public HibernateController(){
ipAddresses = new ArrayList<IPAddress>();
}
public boolean engineIsStarted() {
return isStopped;
}
public boolean engineIsStopped() {
return isStarted;
}
public void startEngine(AjaxBehaviorEvent event){
System.out.println("I am here and started");
isStarted = true;
isStopped = false;
}
public void stopEngine(AjaxBehaviorEvent event){
System.out.println("I am here and stopped");
isStopped = true;
isStarted = false;
}
Snippet of codes in my xhtml
<h:form>
<h:dataTable value="#{hibernateController.ipAddresses}" var="tempAddress"
styleClass="demo-table"
headerClass="demo-table-header"
rowClasses="demo-table-odd-row,demo-table-even-row">
<h:column>
<!-- the column header -->
<f:facet name="header">IP Adress</f:facet>
<!-- the value for each row -->
#{tempAddress.ipAddress}
</h:column>
<h:column>
<!-- the column header -->
<f:facet name="header">Port Number</f:facet>
<!-- the value for each row -->
#{tempAddress.portNumber}
</h:column>
<h:column>
<!-- the column header -->
<f:facet name="header">Action</f:facet>
<!-- the value for each row -->
<h:commandLink value="Update"
action="#{hibernateController.loadAddress(tempAddress.id)}"/>
|
<h:commandLink value="Delete"
onclick="if (!confirm('Are you sure you want to delete this address?')) return false"
action="#{hibernateController.deleteAddress(tempAddress.id)}"/>
</h:column>
<h:column>
<h:commandButton id="startButton" value="start" rendered="#{hibernateController.engineIsStarted()}">
<f:ajax event="click" execute="#this" listener="#{hibernateController.startEngine}" render="#all" />
</h:commandButton>
<h:commandButton id="stopButton" value="stop" rendered="#{hibernateController.engineIsStopped()}">
<f:ajax event="click" execute="#this" listener="#{hibernateController.stopEngine}" render="#all" />
</h:commandButton>
</h:column>
</h:dataTable>
</h:form>
Image of interface now

JSF Ajax CommandButton different level

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

Ajax-update another component inside same composite component

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?

How to pass parameter to f:ajax in h:inputText? f:param does not work

I need to pass a parameter to the server in my ajax request. Please see the code below.
Scope: View Scope
Without f:param
<p:column width="40">
<h:inputText id="originalCostInputTxt" value="#{articlePromo.costoBruto}"
<f:ajax event="change"
execute="#this"
listener="#{promotionDetailManagedBean.onCostoBrutoChange}">
</f:ajax>
</h:inputText>
</p:column>
Managed Bean
public final void onCostoBrutoChange(final AjaxBehaviorEvent event) {
createCostoBrutoOptions(promoArticlesList);
}
In this case, the method onCostoBrutoChange() does gets invoked. But, it does not get invoked when I include f:param. Please see the code below.
With f:param
<p:column width="40">
<h:inputText id="originalCostInputTxt" value="#{articlePromo.costoBruto}"
<f:ajax event="change"
execute="#this"
listener="#{promotionDetailManagedBean.onCostoBrutoChange}">
<f:param value="#{articlePromo.promocionArticuloId}" name="myId"/>
</f:ajax>
</h:inputText>
</p:column>
Managed Bean
public final void onCostoBrutoChange(final AjaxBehaviorEvent event) {
createCostoBrutoOptions(promoArticlesList);
String id = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("myId");
}
Not able to identify whats incorrect in this code. Please guide.
Thanks,
Shikha
The <f:param> works in links and buttons only, not in inputs.
If your environment supports EL 2.2, just pass it as method argument instead:
<h:inputText ...>
<f:ajax listener="#{bean.listener(item.id)}" />
</h:inputText>
public void listener(Long id) {
// ...
}
You can also just pass the whole item:
<h:inputText ...>
<f:ajax listener="#{bean.listener(item)}" />
</h:inputText>
public void listener(Item item) {
// ...
}
If your environment doesn't or can't support EL 2.2, then evaluate EL programmatically instead.
public void listener() {
FacesContext context = FacesContext.getCurrentInstance();
Long id = context.getApplication().evaluateExpressionGet(context, "#{item.id}", Long.class);
// ...
}

Reloading div using Ajax

I have found this topic, where's a bit of code to reload a div using Ajax.
I've tried creating such example, but not successfully.
Here's my code:
index.xhtml
<h:form>
<f:ajax render=":content">
<h:commandButton value="News" action="#{navigationBean.requestPage}">
<f:param name="requestedPage" value="news.xhtml"/>
</h:commandButton>
</f:ajax>
<br/><br/>
<f:ajax render=":content">
<h:commandButton value="News" action="#{navigationBean.requestPage}">
<f:param name="requestedPage" value="games.xhtml"/>
</h:commandButton>
</f:ajax>
</h:form>
</h:panelGroup>
<h:panelGroup id="content" layout="block">
<ui:include src="#{navigationBean.viewedPage}"/>
</h:panelGroup>
backing bean
#ManagedBean
#ViewScoped
public class NavigationBean
{
private String viewedPage;
public NavigationBean()
{
viewedPage = "news.xhtml";
}
public String getViewedPage()
{
return viewedPage;
}
public void setViewedPage(String viewedPage)
{
this.viewedPage = viewedPage;
}
public void requestPage()
{
Map<String,String> map = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap();
viewedPage = map.get("requestedPage");
}
}
how it looks:
So what am I missing? Variable viewedPage is updated, normal labels/texts etc. are updated, but can't get this div working.
Found the solution:
<h:commandButton value="Games" action="#{navigationBean.requestPage}">
<f:param name="requestedPage" value="games.xhtml"/>
<f:ajax execute="#this" render="#none" />
<f:ajax render=":content"/>
</h:commandButton>
plus changing #ViewScoped to #SessionScoped.

Resources