Creating input fields dynamically in JSF 2.0 and linking it to a backing bean - jsf

My requirement is something like this. In a JSF(2.0) page, I have a section called Address. I have added a button which says "Add an Address". When the user clicks the button, new address fields(input text) should be generated dynamically (Line1, Line2, City etc..,). And when I click submit, all the values (Address 1, Address 2 ... Address N) should go to an array list.
So I need to
Dynamically generate UI components on click on a button
Link those UI components to a backing bean (Preferably to a list)
Data tables should not be used for the above
It is very difficult to find proper JSF documentations online, so if anyone can help me out it would be great
Update : The answer posted by noone works good, but I want something more robust, like creating dynamic UI components from the Java Controller (The java bean, using HtmlPanelGrid component). I have been able to create components dynamically using htmlPanelGrid, but I cannot find a way to bind those generated components to the address list in the bean (The one which stores details of all the addresses)

I assume that you have a class Address for the addresses. And a AddressBean with a List to keep the adresses.
The code might look like this (for the most basic scenario I can think of):
<h:form id="addressForm">
<h:commandButton value="Add Address" action="#{addressBean.addAddress()}" immediate="true" execute="#this">
<f:ajax render="addressForm" />
</h:commandButton>
<c:forEach items="#{addressBean.addressList}" var="address">
<h:inputText value="#{address.street}" /><br />
</c:forEach>
<h:commandButton value="Save" action="#{addressBean.persistAddresses}" />
</h:form>
#ManagedBean
#ViewScoped
public class AddressBean {
private List<Address> addressList = new ArrayList<Address>(); // getter+setter
public void addAddress() {
addressList.add(new Address());
}
public void persistAddresses() {
// store the addressList filled with addresses
}
}
public class Address {
private String address; // getter+setter
}
<c:forEach> is taken from the JSTL. It might work with <ui:repeat>, but depending on your actual scenario it might not.

Related

Render XHTML Content with parameter carried by URL [duplicate]

I am trying to pass parameter between two pages.my User.xhtml page has ui:repeat which displays user.I have access to the user Id as well. I want to click on the user and go to their details page. I have userDetails.xhtml which is blank at the moment.
I have a Bean as well.
Currently I am using h:link to navigate one page to another. And it works.
My mission is : Click on the user and get their details.
Please help, I am pretty new in JSF
Thanks
You can try using <f:param>:
<ui:repeat value="#{userBean.users}" var="u">
...
<h:link outcome="userDetails" value="Details">
<f:param name="userID" value="#{u.id}" />
</h:link>
...
</ui:repeat>
then you can get the id like this:
#ManagedBean
#RequestScoped
public class UserDetailsBean {
#ManagedProperty(value = "#{param.userID}")
private String userID;
// Getters and Setters
}

Is it possible to make JSF restore user entered values regardless of the data being valid?

I am working on a JSF app with a form:
<h:inputText value="#{model.firstname}" />
<h:inputText value="#{model.employeeNumber}" converter="javax.faces.Integer"/>
...
Here's the model with bean validation:
#NotNull(message="Please enter a surname")
private String firstname;
#Min(value=1)
#Max(value=2000)
private Integer employeeNumber;
...
//setters and getters
Everything is working nicely apart from the explicitly coded 'back' button within the page which goes to the previous page / form.
I want the values the user entered to restore when they return to the above page again regardless of whether the data is valid.for example, if the user enters abc into the employeeNumber field this String cannot be stored to the Integer on the model.
I understand that JSF stores user entered values into "Request Values" for each UIComponent. It is these I would like to restore rather than that of my model because the above form had not had it's data validated yet.
How can I do this?
(data validation will happen when the user clicks submit).
My colleague has just mentioned there may be a way to accomplish this using omnifaces
As of now, there is. Lot of things were already available in OmniFaces except of only one small missing key part. I just committed a Hacks#getStateHelper() to 2.3 SNAPSHOT which should expose the protected UIComponent#getStateHelper() method into public. Then, it's doable together with help of EditableValueHolderStateHelper already in OmniFaces since 1.0 and with <o:form> and <o:ignoreValidationFailed> in order to invoke action anyway irrespective of conversion/validation errors (as the "back" button should do).
So, if you make sure you use at least OmniFaces 2.3 (currently only available as SNAPSHOT), then you can achieve the requirement with below session scoped helper bean, utilizing several OmniFaces utility classes Faces, Hacks and EditableValueHolderStateHelper:
#Named
#SessionScoped
public class Forms implements Serializable {
private transient Map<String, StateHelper> states = new ConcurrentHashMap<>();
public void saveState(ComponentSystemEvent event) {
UIComponent form = event.getComponent();
FacesContext context = Faces.getContext();
StateHelper state = Hacks.getStateHelper(form);
EditableValueHolderStateHelper.save(context, state, form.getFacetsAndChildren());
states.put(Faces.getViewId(), state);
}
public void restoreState(ComponentSystemEvent event) {
StateHelper state = states.get(Faces.getViewId());
if (state != null) {
UIComponent form = event.getComponent();
FacesContext context = Faces.getContext();
EditableValueHolderStateHelper.restore(context, state, form.getFacetsAndChildren());
}
}
public void removeState() {
states.remove(Faces.getViewId());
}
}
The saveState needs to be invoked during postValidate event of the form component. The restoreState() needs to be invoked during postAddToView event of the form component. The removeState() needs to be invoked during succesful action. Below is an example form:
<o:form>
<f:event type="postAddToView" listener="#{forms.restoreState}" />
<f:event type="postValidate" listener="#{forms.saveState}" />
<h:inputText value="#{bean.string}" required="true" />
<h:inputText value="#{bean.integer}" required="true" />
<h:commandButton value="save" actionListener="#{forms.removeState()}" action="#{bean.save}" />
<h:commandButton value="back" action="#{bean.back}">
<o:ignoreValidationFailed />
</h:commandButton>
<h:messages />
</o:form>
Major advantage of this approach is that no modifications needs to be made to existing validation rules and backing beans, hereby thus keeping all advantages of JSF and BV.
Make sure you clear server session state and/or increase serialVersionUID of Forms class whenever you make changes in the component tree structure of the associated forms, else you'll have to make prechecks and/or properly handle exceptions. Giving the forms and input components a fixed ID is also strongly recommended.
I have dealt with just this problem in the past - by not using the validation annotations such as #NotNull, #Min, and #Max. When using those annotations, invalid data cannot be applied to the model, and so the state cannot be saved on the server.
Instead, I had to code the validation logic in the method behind the Submit button. The downside is that JSF isn't doing the work for you; you have to do it yourself. The upside is that you have more control over exactly when and how the validation is applied.

Primefaces binding datatable with viewscope

I'm currently building an xhtml page based on Primefaces 3.5 (which I can't update...not lucky this time!).
In this page I need to build dynamically different datatables so I thought that unique way to achieve my task is through the binding method.
So I've made:
<p:dataTable id="bindQTable" var="item"
value="#{bindingHtmlTableClass.items}"
binding="#{bindingHtmlTableClass.dataTable}">
<p:column headerText="Name Column">
<h:outputText value="#{item}" />
</p:column>
<p:column>
<p:commandButton value="remove"
action="#{bindingHtmlTableClass.remove}" />
</p:column>
</p:dataTable>
and the bean:
#ManagedBean(name="bindingHtmlTableClass")
#RequestScoped
public class BindingHtmlTableClass implements Serializable{
private List<String> items;
private DataTable dataTable;
#PostConstruct
private void buildUp(){
System.out.println("postconstruct!");
items = new ArrayList<String>();
items.add("X");
items.add("Y");
}
...getters,setters...
}
The problem now is that I would need to update the tables and especially after a poll period I need to update the values within them.
But i'm in a Request Scope and I can't use a View Scope because of binding.
Is there a better way to implement such thing?
EDIT 4 BalusC: why i need binding the datatable? Because i need to show a datatable linked to a serie of different connection to different installation of RabbitMQ, which is not a known number. My boss asked me to put each RabbitMQ server in a different DataTable where each queue is represented in a different row. Each column needs to show actual queue size plus a button or more to manage the queue (purging, deleting...).
Thanks!

#ViewScoped, f:setPropertyActionListener only works once

I have 2 managedBeans: the first one (RequestScoped) sends a parameter to the second one (ViewScoped) through a h:commandLink. Both managedBeans are in the same page, but I use them in different tabs from a rich:TabPanel:
#ManagedBean
#RequestScoped
public class TheRequestScopedManagedBean {
private String number
...
#ManagedBean
#ViewScoped
public class TheViewScopedManagedBean {
private String number;
...
And here's the view, wich uses a rich:dataTable:
(The action method is only for showing the second tab from a rich:tabPanel).
// ... another dataTable's columns
<rich:column>
<f:facet name="header">Number</f:facet>
<b>
<a4j:commandLink value="#{theRequestScopedManagedBean.number}"
render="someRichPanel" action="#{anotherBean.showSecondTab}" immediate="true">
<f:setPropertyActionListener target="#{theViewScopedManagedBean.number}" value="#{theRequestScopedManagedBean.number}" />
</a4j:commandLink>
</b>
</rich:column>
The problem here is that theViewScopedBean shows the value only the first time, and when I try to pass it again, it shows its default value (null).
I've seen several questions on this website. But I really don't know what to do in this case.
action="#{anotherBean.showSecondTab}" is going to result in a navigation case firing. This will in turn result in the views and request scoped beans being destroyed and recreated (as is the expected behaviour for a view scoped bean).
If you're using EL2.2, you could easily just pass the value directly into a method in the view scoped bean. Let's assume your viewscoped bean has a method takeValue, you can pass the parameter directly into the method as in:
<a4j:commandLink value="#{theRequestScopedManagedBean.number}" render="someRichPanel" action="#{theViewScopedBean.takeValue(theRequestScopedManagedBean.number)}" immediate="true"/>
There are still cleaner ways to transmit data between pages.
Communication in JSF2.0

JSF: My dynamically added elements don't react

This questions seems to be so simple, yet I didn't find the mistake.
Ok, here we go: I have a form with a List of IPs (whatever),
IP n: [INPUT-FIELD] [Button "Add"]
IP n+1: [INPUT-FIELD] [Button "Add"]
These IPs exist right from the start.
They are initialized in the Constructor of the Managed Bean.
When I click on the "Add" Button, the current IP is validated. After that
I add another entry to my java.util.List and another line in the
JSF form appears:
IP n+2: [INPUT-Field] [Button "Add"]
and so on.
Adding a line (with a new IP) and validating the current IP
work perfect for the existing values IP n and IP n+1,
but validating and adding does NOT work with the dynamically
added IP n+2. Neither validating the dynamically generated input field
works nor adding another line with the newly created "Add"-Button.
What am I doing wrong?
<h:form id="frmSpecial" prependId="false">
<h:panelGroup id="tblDestFw">
<c:forEach items="#{bean.fwdest}" var="fwdest">
IP: <h:inputText value="#{fwdest.ip}" validator="#{bean.validateIP}"/>
<h:commandButton action="#{bean.addFwDest()}"
value=">>" title="Add another line">
<f:ajax execute="#this" render="tblDestFw"/>
</h:commandButton>
<br/>
</c:forEach>
</h:panelGroup>
</h:form>
#ManagedBean(name = "bean")
#ViewScoped
public class EnterNewSystemFW implements Serializable {
List<FirewallDest> fwdest;
public EnterNewSystemFW() {
fwdest.add(new FirewallDest("N"));
fwdest.add(new FirewallDest("N+1"));
}
public void addFwDest() {
fwdest.add(new FirewallDest());
}
}
Thanks.
Bernd
As to adding the new line, your <c:forEach> references a view scoped bean property. Due to JSF issue 1492, this bean is reconstructed on every request.
Replace it by a normal JSF component like <ui:repeat> or <h:dataTable> and it'll work as expected.
<ui:repeat value="#{bean.fwdest}" var="fwdest">
...
</ui:repeat>
As to performing validation, your <f:ajax execute="#this"> processes only the current component (the command button), not the inputs. Use <f:ajax execute="#form"> instead to process the entire form.
See also:
JSTL in JSF2 Facelets... makes sense?

Resources