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 ;)
Related
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>
I want to 'update' a component with a new component in the bean.
XHTML
<composite:interface>
<composite:attribute name="rootKey" required="true" />
<composite:attribute name="id" required="true" />
</composite:interface>
<composite:implementation>
<rich:panel id="#{cc.attrs.id}" binding="#{myBean.customPanel}"/>
<a4j:jsFunction name="createPanels"
action="#{myBean.createPanels}"
render="#{cc.attrs.id}">
<a4j:param name="rootId" assignTo="#{myBean.rootId}"/>
<a4j:param name="rootKey" assignTo="#{myBean.rootKey}"/>
</a4j:jsFunction>
<script type="text/javascript">
/* <![CDATA[ */
jQuery(document).ready(function() {
createPanels('#{cc.attrs.id}','#{cc.attrs.rootKey}');
});
/*]]> */
</script>
</composite:implementation>
</ui:composition>
Bean
private UIPanel rootPanel;
public void setCustomPanel(UIPanel panel) {
rootPanel = panel;
}
public UIPanel getCustomPanel() {
return rootPanel;
}
public void createPanels() {
//try #1 : Adding new panels as children
rootPanel.getChildren().add((UIPanel)createPanels(rootId,rootKey));
//try #2 : A new Panel component
rootPanel = (UIPanel)createPanels(rootId,rootKey);
...
rootPanel.setId(rootId); // this ID is the same as the 'placeholder' panelId
FacesContext.getCurrentInstance().getPartialViewContext().getRenderIds().add(rootPanel.getId()); // the rerender should also already be done in the XHTML js function.
}
With the debugger i see the rootPanel changes into the new panel component, but not in the view.
What do i miss?
What i try in short: Generating dynamically components as children for the panel component in the xhtml view. The generation needs the 'rootKey' param for generating the right set.
Using:
JSF Mojarra 2.1.19
Richfaces
The solution for me was to rerender te parent, not the actual component.
Also adding the new element children as children to the bound component.
XHTML : Added a h:panelgroup around the place holder.
<h:panelGroup id="#{cc.attrs.id}_parent">
<rich:panel id="#{cc.attrs.id}" binding="#{myBean.panel}"/>
</h:panelGroup>
<a4j:jsFunction name="createPanels"
action="#{myBean.createPanels}"
render="#{cc.attrs.id}_parent">
<a4j:param name="rootId" assignTo="#{myBean.rootId}"/>
<a4j:param name="rootKey" assignTo="#{myBean.rootKey}"/>
</a4j:jsFunction>
BEAN : try #1 was the right one.
public void createPanels() {
UIPanel newPanel = (UIPanel)createPanels(rootId,RootKey);
if(newPanel.getChildCount() >= 1){
rootPanel.getChildren().addAll(newPanel.getChildren());
rootPanel.setStyleClass(newPanel.getStyleClass());
rootPanel.setHeader(newPanel.getHeader());
}
}
I have a form like the following picture.
In the above picture you can see a green add button. When I click on it, it create a new row in a datatable via send a <f:ajax> to backing bean and render <h:datatable>.
Until now all thing is good. But i Except when I click on a cross button inside of each row, that row removed. but it have a bug. for example when I click on the third row cross button, it removes this row from backing bean but not from my ui.
in the following you can see my backing bean and .xhtml file.
#ManagedBean(name = "AddPollContorler")
#ViewScoped
public class AddPollControl {
private List<Answer> answers = new ArrayList<Answer>();
#PostConstruct
public void init(){
answers.add(new Answer());
answers.add(new Answer());
}
public List<Answer> getAnswers() {
return answers;
}
public void setAnswers(List<Answer> answers) {
this.answers = answers;
}
public void addAnswer() {
answers.add(new Answer());
}
public void removeAnswer() {
String index=FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("index");
if (StringUtil.isNumber(index))
answers.remove(Integer.parseInt(index));
}
}
.xhtml :
<div class="panel panel-success rgt">
<div class="panel-heading rgt">
<div style="float: left;">
<h:commandLink styleClass="btn btn-success table-button" action="#{AddPollContorler.addAnswer}">
<h:graphicImage library="img" name="add.png" styleClass=" table-icon" />
<f:ajax execute="answers" render="answers"></f:ajax>
</h:commandLink>
</div>
<h4><h:outputText value="#{msg['protected.poll.add.answers']}"/></h4>
</div>
<div class="form-margin">
<h:dataTable value="#{AddPollContorler.answers}" var="answer" id="answers" style="width:100%;">
<h:column >
<div class="input-group poll-answer" style="margin: 5px;">
<span class="input-group-addon no-left-radius"><h:outputText value="#{CounterControler.index+1}" /></span>
<h:inputText value="#{answer.text}" styleClass="form-control no-radius"/>
<div class="input-group-addon no-right-radius poll-answer-remove" >
<h:commandLink action="#{AddPollContorler.removeAnswer}">
<h:graphicImage library="img" name="cross.png" />
<f:param name="index" value="#{CounterControler.last}" />
<f:ajax render="answers answers" />
</h:commandLink>
</div>
</div>
</h:column>
</h:dataTable>
</div>
</div>
update: 2013/06/12
#ManagedBean(name="CounterControler")
public class CounterControl {
private int index=0;
public int getIndex(){
return index++;
}
public int getLast(){
return index-1;
}
}
your code does look pretty good already. How does the CounterControler internally work? (no source given) Alternatives to send the current object might be
to give the object directly as the parameter (you need a fitting converter for that),
give it as direct parameter (action="#{AddPollContorler.removeAnswer(answer)}, works from EL 2.2 on), or
directly get the current object out of the given ActionEvent
The last point would look like
xhtml
<h:commandLink action="#{AddPollContorler.removeAnswer}">
<h:graphicImage library="img" name="cross.png" />
<f:ajax render="answers" />
</h:commandLink>
managed bean
public void removeAnswer(ActionEvent ev) {
Answer selectedItem = null;
try {
UIDataTable objHtmlDataTable = retrieveDataTable(
(UIComponent)ev.getSource());
selectedItem = (Answer) objHtmlDataTable.getRowData();
answers.remove(answer);
} catch (NullPointerException e) {
// somehow couldn't find the element
}
}
private static UIDataTable retrieveDataTable(UIComponent component) {
if (component instanceof UIDataTable) {
return (UIDataTable) component;
}
if (component.getParent() == null) {
return null;
}
return retrieveDataTable(component.getParent());
}
I like that one because it takes most logic out of the frontend. Hope you get your rows cleaned with one of that tactics.
Also, you only need to mention answers once in <f:ajax render="answers" />
EDIT: Even I don't know why - wrapping a <h:panelGroup layout="block" id=" answersWrapper"> around the <h:dataTable> and rendering that panelGroup worked for me.
<h:form id="myForm">
<h:panelGroup id="answerWrapper" layout="block">
<rich:dataTable value="#{myTestBean.answers}" var="answer" id="answers">
<h:column >
<h:outputText value="#{answer}"/>
<h:commandButton id="button" action="#{myTestBean.doTheAction}">
<f:ajax render=":myForm:answerWrapper" />
</h:commandButton>
</h:column>
</rich:dataTable>
</h:panelGroup>
</h:form>
I am using IceFaces components and I am trying to fill up a select with some values that correspond to a MangedBean property.
<h:form>
<ice:selectOneMenu size="1" style="width: 180px">
<f:selectItem value="#{stockManagedBean.listeCategoriesItem}"></f:selectItem>
</ice:selectOneMenu>
</h:form>
listeCategoriesItem is a property of StockManagedBean and is an ArrayList of SelectItem.
#ManagedBean
public class StockManagedBean {
CategorieDAO categorieDAO;
List<SelectItem> listeCategoriesItem;
public StockManagedBean() {
categorieDAO = new CategorieDAO();
listeCategoriesItem = new ArrayList<SelectItem>();
List<Categorie> listeCategories = categorieDAO.selectAllCat();
for(Categorie categorie: listeCategories) {
listeCategoriesItem.add(new SelectItem(categorie.getCatId(), categorie.getCatNom()));
}
}
public List<SelectItem> getListeCategoriesItem() {
return listeCategoriesItem;
}
public void setListeCategoriesItem(List<SelectItem> listeCategoriesItem) {
this.listeCategoriesItem = listeCategoriesItem;
}
}
I tested the values that come from my DAO and they are all correct. I also tested the values of the list in the getter and they are also correct, but when I load my html page, nothing is in the select list...
Use <f:selectItems> instead of <f:selectItem>. Note the s at the end of the former component.
<ice:selectOneMenu size="1" style="width: 180px">
<f:selectItems value="#{stockManagedBean.listeCategoriesItem}" />
</ice:selectOneMenu>
Also, it would be good to also have a field in your bean that will handle the value of the selected item in your selectOneMenu.
<ice:selectOneMenu size="1" style="width: 180px"
value="#{stockManagedBean.selectedCategory}">
<f:selectItems value="#{stockManagedBean.listeCategoriesItem}" />
</ice:selectOneMenu>
And in your managed bean:
#ManagedBean
public class StockManagedBean {
private String selectedCategory;
//rest of your code
//getters and setters...
}
I have two primefaces panel components in jsf page.I want to show some data on panels via clicking primefaces commandButton and show panel1 when page load.When clicking commandbutton,I do not want to show other panel.So I defined boolean variables in backing bean to use in visible property of panels.But it does not work.
Backing Bean:
#ManagedBean
#SessionScoped
public class Bean implements Serializable {
private boolean show;
#PostConstruct
public void init(){
this.show=true;
}
public void action_commandButton(){
this.show=false;
}
}
Jsf Page
<p:commandButton style="text-align: center;font-size:12px;"
action="#{bean.action_commandButton()}" value=""/>
<!--panel 1 -->
<p:panel visible="#{bean.show}">
<p:dataGrid>
<!-- data from datbase-->
</p:dataGrid>
</p:panel>
<!-- panel 2-->
<p:panel visible="#{!bean.show}">
<p:dataGrid>
<!-- data from datbase-->
</p:dataGrid>
</p:panel>
How to solve this problem?
Thanks in advance.