Generate h:panelGrid from Java list [duplicate] - jsf

I am wondering how to display a List<T> as obtained below in a Facelet:
public List<T> searchByString(String string) {
return getEntityManager().createNamedQuery("Userdetails.findByUsername").setParameter("username", "%" + string + "%").getResultList();
}
Would a <h:dataTable> be a suitable way?

You're going need to iterate over it. JSF 2 offers three iteration components out the box. Provided that the User entity look like below,
#Entity
public class User {
private #Id Long id;
private String username;
private String email;
private LocalDate birthdate;
// Add/generate getters+setters.
}
and that the search results are assigned as a List<User> users property of a bean which is available as #{bean},
#Named #RequestScoped
public class Bean {
private List<User> users;
// Add/generate postconstruct+getter.
}
here are some examples based on it:
<h:dataTable>, an UI component which generates a HTML <table>.
<h:dataTable value="#{bean.users}" var="user">
<h:column>#{user.id}</h:column>
<h:column>#{user.username}</h:column>
<h:column>#{user.email}</h:column>
<h:column>#{user.birthdate}</h:column>
</h:dataTable>
<ui:repeat>, an UI component which generates no HTML markup (so, you'd have to write all that HTML in the desired fashion yourself, which could easily be changed to e.g. <ul><li>, or <dl><dt><dd>, or <div><span>, etc):
<table>
<ui:repeat value="#{bean.users}" var="user">
<tr>
<td>#{user.id}</td>
<td>#{user.username}</td>
<td>#{user.email}</td>
<td>#{user.birthdate}</td>
</td>
</ui:repeat>
</table>
<c:forEach>, a tag handler which runs during view build time instead of view render time (background explanation here: JSTL in JSF2 Facelets... makes sense?), it also doesn't produce any HTML markup:
<table>
<c:forEach items="#{bean.users}" var="user">
<tr>
<td>#{user.id}</td>
<td>#{user.username}</td>
<td>#{user.email}</td>
<td>#{user.birthdate}</td>
</td>
</c:forEach>
</table>
See also:
Java EE 6 tutorial - Adding components to a page - using <h:dataTable>
How and when should I load the model from database for h:dataTable

You can save your List in a class variable, give it a getter and (maybe) a setter. Declare searchByString method as void and call it with let's say a (provided you are using PrimeFaces):
<p:commandLink update="#form" process="#this" action="#{myBean.searchByString}">
myBean:
public void searchByString(String string) {
userList = getEntityManager().createNamedQuery("Userdetails.findByUsername").setParameter("username", "%" + string + "%").getResultList();
}
provided your table sits in a form that you just updated you could display the List in it.
<p:dataTable var="user" value="#{myBean.userList}">
<p:column headerText="Name">
<h:outputText value="#{user.name}" />
</p:column>
</p:dataTable>

Related

Added String to ArrayList not shown / not updated [duplicate]

This question already has answers here:
How to send form input values and invoke a method in JSF bean
(1 answer)
Pass an input value directly as action method argument
(1 answer)
Using <ui:repeat><h:inputText> on a List<String> doesn't update model values
(1 answer)
Closed 5 years ago.
...So i've got my #ApplicationScoped Bean "Application"..:
#ManagedBean(name = "Application")
#ApplicationScoped
public class Application implements Serializable {
private boolean isRunning = false;
private ArrayList<Feed> sentNotifications = new ArrayList<>();
private ArrayList<String> emails = new ArrayList<>(
Arrays.asList("f00#b4r.com", "test#test.com")
);
private LinkedList<String> words = new LinkedList<>(
Arrays.asList("vuln","banana","pizza","bonanza")
);
private LinkedList<String> feeds = new LinkedList<>(
Arrays.asList("http://www.kb.cert.org/vulfeed",
"https://ics-cert.us-cert.gov/advisories/advisories.xml",
"https://ics-cert.us-cert.gov/alerts/alerts.xml")
);
...and want to add a String to ArrayList<String> emails using the method:
public String addEmail(String email) {
emails.add(email);
return null;
}
The Facelet goes as follows:
<!-- EMAILS -->
<h3>Configured Emails</h3>
<h:form>
<h:inputText value="Email" var="email"/>
<h:commandButton value="Add Email" action="#{Application.addEmail(email)}"/>
</h:form>
<h:form>
<ui:repeat var="email" value="#{Application.emails}">
<tr>
<td>#{email}</td>
<td>
<f:facet name="header">Action</f:facet>
<h:commandLink value="Delete" action="#{Application.rmEmail(email)}"/>
</td>
</tr>
<br></br>
</ui:repeat>
</h:form>
...so when i try to add "blabla#bla.com", this is the Result:
There is a delete-button shown, but not the String itself?!
Is the String correctly added - and JSF doesnt rerender the view..?
..Or is the String not added correctly?
please help!
thanks.
I fixed it, finally!
Thanks to User #Kukeltje, who hinted me at basic things that i got wrong - and User #Wietlol who motivated me in the chat through moral support and 'believes in me' :)
The solution:
..in Application.java:
public List<Feed> sentNotifications = new ArrayList<>();
public List<String> emails = new ArrayList<>();
public List<String> words = new LinkedList<>(Arrays.asList("vuln", "banana", "pizza", "bonanza"));
public List<String> feeds = new LinkedList<>(
Arrays.asList("http://www.kb.cert.org/vulfeed",
"https://ics-cert.us-cert.gov/advisories/advisories.xml",
"https://ics-cert.us-cert.gov/alerts/alerts.xml")
);
private String currentEmail;
private String currentFeed;
private String currentWord;
[...]
public void addEmail() {
emails.add(currentEmail);
}
..and gui.xhmtl:
<!-- EMAILS -->
<h3>Configured Emails</h3>
<h:form>
<h:inputText value="#{Application.currentEmail}" var="email"/>
<h:commandButton value="Add Email" action="#{Application.addEmail}"/>
</h:form>
<h:form>
<ui:repeat var="email" value="#{Application.emails}">
<tr>
<td>#{email}</td>
<td>
<f:facet name="header">Action</f:facet>
<h:commandLink value="Delete" action="#{Application.rmEmail(email)}"/>
</td>
</tr>
<br></br>
</ui:repeat>
</h:form>
Notice how action="#{Application.addEmail}" does not make use of arguments- rather the parameter is handed to the method via value="#{Application.currentEmail}".
If you, reader, have the same problem please consider these points:
getter/setter for each Field in the bean
primitive fields!
argument-less methods to 'delegate' the primitive Fields, e.g. my addEmail method
Hope this answer is usefull to ppl having the same issue!
Greetings,
Gewure

How do I display a list of strings in JSF which also needs to be editable?

I have a backing bean which has a property called List cites where Cite has a string property called "value" .. In the init method I am fetching the values stored as a comma separated string, splitting them into individual strings constructing a list and displaying the list of cites. But I also want to give the users ability to add more cites on top of existing ones/edit existing cite content. How can I do that ? The code below is the jsf in xhtml but it doesn't work for me ..
<div style="margin-top: 10px; padding: 3px 3px;">
<fieldset>
<legend>Cites Affected</legend>
<h:dataTable value="#{dataEntry.cites}" var="citeAffected">
<h:column>
<f:facet name="header" >
<h:outputText value="Cite"/>
</f:facet>
<h:inputText value="#{citeAffected.value}"/>
</h:column>
</h:dataTable>
<h:commandButton value="Add cite" process="#this" action="#{dataEntry.addCite}"/>
</fieldset>
</div>
In the backing bean .. this is what I have
DataEntry
{
private List<CiteAffected> cites = new ArrayList<CiteAffected>();
public void addCite()
{
cites.add(new CiteAffected());
}
public void editMetadata()
{
//update the db object
}
private void init()
{
// get the value from database as a comma separated string
for(String citeAffected : Arrays.asList(sourceManualLoadProperties.getCitesAffected().split(",")))
{
CiteAffected cite = new CiteAffected();
cite.setValue(citeAffected);
this.cites.add(cite);
} }
}
The error I am getting is .. As soon as I click on the command button "add cite" all the existing values disappear when I want it to simply add another text box but display the existing values as well ..
public class CiteAffected
{
private String value;
/**
*
* #return the cite affected
*/
public String getValue()
{
return value;
}
/**
*
* #param value the cite affected
*/
public void setValue(final String value)
{
this.value = value;
}
}
Just remove the process="#this" from <h:commandButton> and have your managed bean in #ViewScoped at least.
JSF code:
<h:form>
<h:dataTable id="dtCites" value="#{dataEntry.cites}" var="citeAffected">
<!-- content... -->
</h:dataTable>
<h:commandButton value="Add cite" action="#{dataEntry.addCite}">
<f:ajax render="dtCites" />
</h:commandButton>
</h:form>
Managed bean:
#ManagedBean
#ViewScoped
public class DataEntry {
//...
}

how to bind dynamic list of composite components to panelGroup

composite component xhtml:
<composite:interface componentType="metroComponent">
<composite:attribute name="uniqueId" />
</composite:interface>
<composite:implementation>
<rich:panel width="100%" header="#{msgs['pages.metroEth.header2']}">
<table class="resData">
<tr>
<td class="labelLeft"><h:outputLabel id="optionLabelId"
value="#{msgs['pages.ccparams.serviceOption']}" /></td>
<td><h:inputText id="optionTextId"
binding="#{cc.serviceOption}" size="15" /> <h:message
for="ccvodTextId" style="color:red" /></td>
</table>
</rich:panel>
</composite:implementation>
</ui:composition>
component type implementation is as follow:
#FacesComponent (value="metroComponent")
public class HtmlMetroCC extends UIComponentBase implements NamingContainer {
UIInput serviceOption;
public UIInput getServiceOption() {
return serviceOption;
}
public void setServiceOption(UIInput serviceOption) {
this.serviceOption = serviceOption;
}
#Override
public String getFamily() {
return "javax.faces.NamingContainer";
}
}
there is also a backing bean which prepare panelGroup element with list of presented above composite components. i removed getters/setters for better reading
#ManagedBean (name="metroethernetBean")
#RequestScoped
public class MetroEthernetMBean implements IBean{
private MetroEthCCData metroCCData;
private HtmlPanelGroup metroCCPanel;
private List<HtmlMetroCC> metroCClist;
#PostConstruct
public void initBean(){
metroCClist = new ArrayList<HtmlMetroCC>();
metroCCPanel = new HtmlPanelGroup();
HtmlMetroCC initialMetroCC = new HtmlMetroCC();
metroCClist.add(initialMetroCC);
processMetroCCPanel();
}
private void processMetroCCPanel(){
metroCCPanel.getChildren().clear();
for (HtmlMetroCC comp: metroCClist){
metroCCPanel.getChildren().add(comp);
}
}
}
page fragment responsible for displaying panelGroup looks like this:
<h:panelGroup id="metroCCPanelGrouId" binding="#{metroethernetBean.metroCCPanel}" />
the question is, why my composite components are not presented on panel? it looks panel has no children added at all..
when I put it as follows on page:
<gui:metroCC />
then composite comp. is displayed properly on page. What i want to achive is a panel on page with composite components which can be added or removed dynamically by clickin add new or delete selected
There is a wrokaround, instead of binding dynamically created panel in menaged bean
<h:panelGroup id="metroCCPanelGrouId" binding="#{metroethernetBean.metroCCPanel}" />
use mBean to initialize list/add new/ remove and loop through it on page:
<h:panelGroup id="metroCCPanelGrouId">
<ui:repeat var="test" value="#{metroethernetBean.metroCClist}">
<gui:metroCC binding="#{test}" />
</ui:repeat>
</h:panelGroup>
BUT: still don't understand why doing it with my first aproach fails...... BaluC, where are you ;)

JSF h:selectBooleanCheckbox inside ui:repeat - varStatus.index works, var doesn't

Can someone please explain this phenomenon?
I am using Mojarra 2.1.6 - Glassfish 3.1.2.
I have a checkbox inside a ui:repeat. The ui:repeat is looping over a list of booleans from my managed bean. Each individual checkbox is bound to an element of that list. For example:
<ui:repeat var="checkbox" value="#{checkboxTestBean.list}" varStatus="status">
<h:selectBooleanCheckbox value="#{checkbox}"/>
</ui:repeat>
The problem is the values aren't getting applied to the managed bean. When I submit and re-render the form, the values don't stick.
However, if I index into the managed bean element explicitly, by changing value=#{checkbox} above to value="#{checkboxTestBean.list[status.index]}", everything works.
Any ideas why that might be the case?
XHTML:
<h:form>
<div>
Using value="#\{var\}"
<ui:repeat var="checkbox" value="#{checkboxTestBean.list}" varStatus="status">
<h:selectBooleanCheckbox value="#{checkbox}"/>
</ui:repeat>
</div>
<div>
Using value="#\{varStatus.index\}"
<ui:repeat var="checkbox" value="#{checkboxTestBean.list}" varStatus="status">
<h:selectBooleanCheckbox value="#{checkboxTestBean.list[status.index]}"/>
</ui:repeat>
</div>
<h:commandLink actionListener="#{checkboxTestBean.actionListener}">
PROCESS FORM
<f:ajax execute="#form" render="#form"/>
</h:commandLink>
</h:form>
Java:
#ManagedBean
#ViewScoped
public class CheckboxTestBean {
public List<Boolean> list = new ArrayList<Boolean>();
public CheckboxTestBean() {
for (int i = 0; i < 5; i++) {
list.add(Boolean.FALSE);
}
}
public void actionListener(ActionEvent evt) {
System.out.println("*** dumping whole form");
System.out.println("*** list = " + list);
}
public List<Boolean> getList() {
return list;
}
public void setList(List<Boolean> list) {
this.list = list;
}
}
That's because the Boolean as being an immutable class doesn't have a setter method for the value. When referencing it as a list item by index instead, EL will be able to set the new value on the List by index like so list.add(status.index, newValue). An alternative is to make it a property of a mutable model class and have a collection of it instead like so List<Item> which you reference by <h:selectBooleanCheckbox value="#{item.checkbox}"/>.
This is not specifically related to Boolean, you would have exactly the same problem when using for example List<String> in an <ui:repeat><h:inputText>.
See also:
Using <ui:repeat><h:inputText> on a List<String> doesn't update model values

JSF LInk to View Page

I have a page with a data table. I want some of the items in the tables to be linked to a corresponding view page.
For example, right now I have a table with no links:
<h:dataTable var="bean" value="#{beanServiceImpl.beans}" border="1">
<h:column>#{bean.id}</h:column>
</h:dataTable>
I want to add hyperlinks to some entries and have them go to a view page showing them more info based on their id:
<h:dataTable var="bean" value="#{beanServiceImpl.beans}" border="1">
<h:column>
#{bean.id}
</h:column>
</h:dataTable>
ViewBean.xhtml will contain something like this:
ViewBean.xhtml
<ul>
<li>ID: #{bean.id}</li>
<li>Field 1: #{bean.field1}</li>
<li>Field 2: #{bean.field2}</li>
</ul>
How do I accomplish something like this in JSF? I know that I'll have to write a controller to query the id for the other fields. But how do I make viewBean.xhtml run the business logic to get the other fields and render it?
The BalusC's answer is almost good, but will not work (edit: it works now).
You already know, how to add the value to the params. BTW, if I were you, I would not use <a href>, but instead:
<h:link outcome='viewBean'>
<f:param name='id' value='#{bean.id}' />
</h:link>
Now you have to choices when it comes to catching the value. The simplest would be to add annotation above your id property:
#ManagedProperty("#{param.id}") // this will inject id from param into id
private Long id;
// (getters and setters are obligatory)
#PostConstruct // this will execute init() after id is injected
public void init() {
}
And the last thing: having a variable named "bean" has no more sense than calling it "variable" (or having a dog named Dog and cat named Cat). It carries no information and worse, it makes all the beans in your application indistinguishable (unless you build a legumes manager).
I'll assume JSF 2.x. Add this to your Bean
#ManagedProperty(value="#{param.id}")
private Long id;
(this does basically a bean.setId(request.getParameter("id")) whenever the view loads)
It'll be available in #PostConstruct method of Bean.
#PostConstruct
public void init() {
// Fill model based on id.
}
This is what I did.
<h:form>
<h:commandLink action="#{bean.populateBean}" value="#{bean.id}">
<f:setPropertyActionListener target="#{bean.id}" value="#{bean.id}" />
</h:commandLink>
</h:form>
In my Bean.java class, I added the action controller:
public String populateBean(){
Bean bean = BeanServiceImpl.getBean(id); //id was injected by the commandLink
this.field1 = tenure.getField1();
this.field2 = tenure.getField2();
return("viewBean");
}
My ViewBean.xhtml is the same:
<ul>
<li>ID: #{bean.id}</li>
<li>Field 1: #{bean.field1}</li>
<li>Field 2: #{bean.field2}</li>
</ul>

Resources