I query from database and I receive an integer list. Ex: 0, 1, 2
If I display the digits to browser, users will not understand the meaning of number.
So, I would like to map a digit to a string.
Ex: 0: Pending, 1: Active, 2: Inactive, so on.
File display.xhtml will have the source code follow as:
<!--display.xhtml-->
<t:dataTable id="itemTable" value="#{itemBrowser.itemList}" var="item">
<t:column>
<f:facet name="header">
<h:outputText value="Status" />
</f:facet>
<h:outputText value="#{itemStatusListReversedString[item.status]}" />
</t:column>
</t:dataTable>
<!--faces-config.xml-->
<managed-bean>
<managed-bean-name>itemStatusListReversedString</managed-bean-name>
<managed-bean-class>java.util.HashMap</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
<map-entries>
<key-class>java.lang.String</key-class>
<map-entry>
<key>0</key>
<value>Inactive</value>
</map-entry>
<map-entry>
<key>1</key>
<value>Active</value>
</map-entry>
<map-entry>
<key>2</key>
<value>Pending</value>
</map-entry>
</map-entries>
</managed-bean>
But, there is nothing to output in browser. So, how can I fix this issue?
Thanks
I think the problem is in this line:
<h:outputText value="#{itemStatusListReversedString[item.status]}" />
You have to do something like this
<h:outputText value="#{item.stringValue}" />
and in the item class add something like this:
public String getStringValue(){
return itemStatusListReversedString.get(this.numberValue);
}
You must change the item class previously in the faces-config to inject a itemStatusListReversedString.
Example:
itemBrowser.itemList is a List of a objects of MyClass:
public class MyClass{
//The necessary stuff
private Integer valueFromDB; //0, 1, 2...
private Map<Integer, String> itemStatusListReversedString; //The map you configured in the faces-config.xml
//More stuff
public String getStringValue(){
return itemStatusListReversedString.get(this.valueFromDB);
}
}
In the faces-config.xml you configure MyClass this way:
<bean id="myClassInstance"
class="package.MyClass" scope="request">
<property name="itemStatusListReversedString" ref="itemStatusListReversedString"></property>
</bean>
When creating new instances of MyClass use this approach instead of creating them using new MyClass():
WebApplicationContext webApplicationContext = FacesContextUtils.getWebApplicationContext(FacesContext.getCurrentInstance());
MyClass bean = (MyClass)webApplicationContext.getBean("myClassInstance");
Use enum then work with ordinal() for the numbers and values() for the text like:
YourEnum.values()[ordinal]
Related
I have an application that uses Spring Boot and jsf. In case I named #Component class the same as the name of the DataModel class in jsf, in the .xhtml file when calling the DataModel's property, it is interpreted as the #Component class.
In the example below although cardDataModel always has data, it seems that card.employeeName is accessing #Component("card") instead of cardDataModel. Just to be sure I remove #Component("card") and the error goes away.
Can anyone help me explain why? Is there a way to limit #Component class? only let it use in Bean only. Or if it can't be limited, is there any warning mechanism when naming the same #Component or DataModel.
Thank you very much
CAP10Bean.java
#Controller("CAP10Bean")
public class CAP10Bean implements Serializable {
private DataModel cardDataModel = new ListDataModel();
public void initCAP10Bean(){
// assume that there is always data, Card.employeeName is not null
createCardList();
}
private void createCardList(){
List<Card> cardList = this.Service.findCard(ID);
this.cardDataModel.setWrappedData(cardList);
}
}
}
CAP1001l.xhtml
<rich:dataTable value="#{CAP40Bean.cardDataModel}" var="card" rowKeyVar="rowIndex">
<f:facet name="header">
<rich:columnGroup>
<rich:column>
<h:outputText value="employee"/>
</rich:column>
</rich:columnGroup>
</f:facet>
<rich:column>
<!-- ERROR -> card.employeeName is null -->
<h:outputText value="#{card.employeeName}" rendered="#{card.employeeName != null}" />
</rich:column>
</rich:dataTable>
Card.java
#Component("card")
public class Card implements java.io.Serializable {
private String employeeName;
}
i m facing to a struts validator problem.
I has an object like this:
public class Reconstitution {
private List<FormuleReconstitution> formuleList;
...
...some other attributes and methods...
}
and :
public class FormuleReconstitution{
private Map<Long, ElementFormuleReconstitution> serieMap;
...
...some other attributes and methods...
}
and
public class ElementFormuleReconstitution {
private Double coefficient;
}
i would like to add a validator on coefficient in MyAction-validation.xml but i don't know how to do this. I know how to add a simple validator but not when i have sublist with submap :(
my generated html code look like this :
<input type="text" class="texte" id="reconstitutionformuleList0listeElementFormuleReconstitution0coefficient" tabindex="0" value="" name="reconstitution.formuleList[0].listeElementFormuleReconstitution[0].coefficient"/>
how can i add a validator on the field Coefficient ?
To validate an object inside a List, you need to use the Visitor Validator.
Then, to validate a double with min/max range, you need:
<field name="coefficient">
<field-validator type="double">
<param name="minInclusive">0.0</param>
<param name="maxInclusive">1000.0</param>
<message>
The coefficient must be between ${minInclusive} and ${maxInclusive}
</message>
</field-validator>
</field>
Finally, I suggest you to read how the INPUT result works (for both Validation and Conversion errors)
I have bean "RichFacesTreeNodeBean" with property "newItemInfo", and I call modal panel with inputTextArea, which must contain actual value of that property, but it contains the first value of property all the time. Here is the part of index.xhtml:
<rich:popupPanel id="editPanel">
<h:form>
<h:inputTextarea value="#{richFacesTreeNodeBean.newItemInfo}" />
<!-- some buttons -->
</h:form>
</rich:popupPanel>
And RichFacesTreeNodeBean.java:
#ManagedBean
#ViewScoped
public class RichFacesTreeNodeBean {
private String newItemInfo;
public String getNewItemInfo() {
return newItemInfo;
}
How to fix this?
<h:form>
<a4j:outputPanel layout="block" ajaxRendered="true">
<h:inputTextarea value="#{richFacesTreeNodeBean.newItemInfo}" />
</a4j:outputPanel>
</h:form>
It works.
I have a page where I have a static list containing the list of products which are again grouped into product groups.I have a toggle button in the JSP page which shuffles between the enabled and disabled products .Code for my toggle button is as follows
<h:commandButton value="retrieve" image="#{displayProductsBean.productsToggleImage}" actionListener="#{displayProductsBean.fetchProductsBasedOnStatus}">
<c:choose>
<c:when test="${displayProductsBean.productFetchCriteria=='0'}">
<f:attribute name="buttonSelected" value="1" />
</c:when>
<c:otherwise>
<f:attribute name="buttonSelected" value="0" />
</c:otherwise>
</c:choose>
</h:commandButton>
Now in the managed bean I am able to get the value of the button selected and have logic to retrieve either enabled or disabled products
But I don't know how would I get back to the same page and also I don't want the list to be reloaded again from the DB.Code in my bean class is as follows
public void fetchProductsBasedOnStatus(ActionEvent event)
{
System.out.println("The fetchProductsBasedOnStatus in bean is called");
String selected = (String) event.getComponent().getAttributes().get("buttonSelected");
System.out.println("The value of toggle button is"+selected);
setProductFetchCriteria(Integer.parseInt(selected));
System.out.println("The value of toggle button is"+this.toString());
}
Somebody please help me resolve this .....
But I don't know how would I get back to the same page
Just return null or void in action method.
and also I don't want the list to be reloaded again from the DB
Just don't do that? If you keep the bean in the view scope and load the lists in the (post)constructor, then the same lists will be kept as long as the enduser is interacting with the same view. You should only not use JSTL tags as it breaks the view scope.
Your code can be simplified as follows:
<h:commandButton value="retrieve" image="#{bean.showDisabledProducts ? 'enabled' : 'disabled'}.png" action="#{bean.toggle}">
<f:ajax render="#form" />
</h:commandButton>
<h:dataTable value="#{bean.products}" ...>
...
</h:dataTable>
with
#ManagedBean
#ViewScoped
public class Bean {
private boolean showDisabledProducts;
private List<Product> enabledProducts;
private List<Product> disabledProducts;
#EJB
private ProductService service;
#PostConstruct
public void init() {
enabledProducts = service.listEnabledProducts();
disabledProducts = service.listDisabledProducts();
}
public void toggle() {
showDisabledProducts = !showDisabledProducts;
}
public List<Product> getProducts() {
return showDisabledProducts ? disabledProducts : enabledProducts;
}
public boolean isShowDisabledProducts() {
return showDisabledProducts;
}
}
I have a (request-scoped) list from which the user may select a "PQ" (list of links). When clicked or otherwise entered into the browser the main page for each PQ shall be displayed. Each PQ's page is of the form
http://localhost:8080/projectname/main.jsf?id=2
Here's the PQ bean first:
#Named
#ViewScoped
public class PqHome implements Serializable
{
#PersistenceContext(unitName="...")
private EntityManager em;
private Integer id;
private PQ instance;
#PostConstruct
public void init()
{
System.out.println("ID is " + id); // ID from URL param
instance = em.find(PQ.class, id);
}
public Integer getId()
{
return id;
}
public void setId(Integer id)
{
this.id = id;
}
public PQ getInstance()
{
return instance;
}
}
Here's the main.xhtml:
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
...>
<ui:define name="metadata">
<f:metadata>
<f:viewParam name="id" value="#{pqHome.id}">
<f:convertNumber integerOnly="#{true}" />
</f:viewParam>
<!--f:event type="preRenderView" listener="#{pqHome.init}" /-->
</f:metadata>
</ui:define>
<ui:define name="title">
<h:outputText value="Main" />
</ui:define>
...
</ui:composition>
Any time I select or otherwise refresh the page/URL I get a NullPointerException from the EntityManager:
org.jboss.weld.exceptions.WeldException: WELD-000049 Unable to invoke [method] #PostConstruct public de.mycomp.myproj.beans.PqHome.init() on de.mycomp.myproj.beans.PqHome#4f0ea68f
at org.jboss.weld.bean.AbstractClassBean.defaultPostConstruct(AbstractClassBean.java:595)
...
Caused by: java.lang.IllegalArgumentException: id to load is required for loading
at org.hibernate.event.spi.LoadEvent.<init>(LoadEvent.java:87)
at org.hibernate.event.spi.LoadEvent.<init>(LoadEvent.java:59)
at org.hibernate.internal.SessionImpl.get(SessionImpl.java:961)
at org.hibernate.internal.SessionImpl.get(SessionImpl.java:957)
at org.hibernate.ejb.AbstractEntityManagerImpl.find(AbstractEntityManagerImpl.java:787)
at org.hibernate.ejb.AbstractEntityManagerImpl.find(AbstractEntityManagerImpl.java:762)
at org.jboss.as.jpa.container.AbstractEntityManager.find(AbstractEntityManager.java:221)
at de.mycomp.myproj.beans.PqHome.init(PqHome.java:47)
... 56 more
[Line 47 is em.find(...)]
The line
<f:event type="preRenderView" listener="#{pqHome.init}" />
doesn't make things any better. I'm pretty desparate now.
How do you get URL GET request params into an #ViewScoped bean?
Note: I bet it's not a trivial thing to do. Chances are I'm doing something wrong here conceptually, so any tips on how to improve are welcome. I felt that I needed to choose #ViewScoped because there will be more complex AJAX-based GUI on that page which I'd really like to keep accessible via URL GET params.
Thanks
There is a better way to get id from url. Just use it in #PostConstruct init() method to get "id" from url:
FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("id");
You can still use ViewScoped and #PostConstruct.
The #PostConstruct is invoked directly after bean's construction and all dependency injection (such as #PersistenceContext, #EJB, #ManagedProperty, #Inject, etc..etc..).
The <f:viewParam> sets its value during the update model values phase, which is far after (post)construction of the bean. So inside the #PostConstruct the <f:viewParam> value is simply not yet been set. It'll be still null at that point.
You're close with <f:event type="preRenderView">, but you have to remove the #PostConstruct annotation.
So:
<f:viewParam name="pq" value="#{pqHome.id}">
<f:convertNumber integerOnly="#{true}" />
</f:viewParam>
<f:event type="preRenderView" listener="#{pqHome.init}" />
with
private Integer id;
public void init() {
instance = em.find(PQ.class, id);
}
Unrelated to the concrete problem, I'd suggest to use a Converter for this instead. See also Communication in JSF 2.0 - Converting and validating GET request parameters.
Also the combination #Named #ViewScoped won't work as intended. The JSF-specific #ViewScoped works in combination with JSF-specific #ManagedBean only. Your CDI-specific #Named will behave like #RequestScoped this way. Either use #ManagedBean instead of #Named or use CDI-specific #ConversationScoped instead of #ViewScoped.