I've tried to follow the solution in f:param or f:attribute support on primefaces autocomplete? to pass a parameter to primefaces 3.3.1 autocomplete component with no success. If I iterates in the Map returns by UIComponent.getCurrentComponent().getAttributes, it doesn't contain the attribute name I set in the .xhtml file, so I get a null pointer when I try to get the attribute. Is there any changes in primefaces implementation after the solution above?
I'm using Eclipse Indigo with Glassfish 3.1.2 and Mojarra 2.0.9.
Part of my code
xhtml :
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui"
xmlns:pe="http://primefaces.org/ui/extensions"
template="WEB-INF/template.xhtml">
...
<p:autoComplete
id="sourceSubMemberLookup" value="#{transactionTransferBacking.sourceSubMember}"
size="64"
completeMethod="#{transactionTransferBacking.completeSourceOpSubMember}"
var="smb" itemLabel="#{smb.displayText}" itemValue="#{smb}"
converter="opSubMemberConverter"
forceSelection="true" dropdown="true"
required="true" rendered="#{loggedInUser.subMemberType eq 1}" >
<f:attribute name="attrSourceMemberId" value="#{transactionTransferBacking.sourceMember.Id">
</p:autoComplete>
...
</ui:composition>
java :
package com.mysoft.backing;
import java.io.Serializable;
import javax.faces.context.FacesContext;
import javax.faces.context.Flash;
import javax.servlet.http.HttpServletRequest;
import javax.enterprise.context.RequestScoped;
#Named
#ManagedBean
#RequestScoped
public class TransactionTransferBacking implements Serializable {
...
public List<OpSubMember> completeSourceOpSubMember(String query) {
List<OpSubMember> members=null;
//Retrieve list of submembers based on partial user input (autocomplete)
//Based on loggedInUser own member's memberId
FacesContext context = FacesContext.getCurrentInstance();
if (context==null) this.getLogger().debug("completeSourceOpSubMeber: faces is null");
UIComponent current = UIComponent.getCurrentComponent(context);
this.getLogger().debug("completeSourceOpSubMember: currentComponent="+current.getId());
//Map<Object, Object> attrMap = context.getAttributes();
Map<String, Object> attrMap = current.getAttributes();
for (Map.Entry entry : attrMap.entrySet()) {
this.getLogger().debug("completeSourceOpSubMember: attrMap.Key="+entry.getKey());
}
int memberId = (int) attrMap.get("attrSourceMemberId");
this.getLogger().debug("completeSourceOpSubMember: MemberId from attribute = "+memberId);
...
return members;
}
}
The log correctly print the current component name as the desired AutoComplete, but the problem is "attrSourceMemberId" is not in the "attrMap" Map, as printed in the log.
Thank you, guys.
Related
We are migrating a JSF 2.1 application, from JBoss AS 7.2 to Wildfly and thus JSF 2.2. The problem We're having is the following: We have a compositecomponent that is included in a #ViewScoped bean. The component has to retain its value through multiple requests, so a Request Scoped bean is not a solution.
The exception we're getting is a multiple component id one. After the request JSF starts to render the component for the second time, and fails.
I made a simple demo for this:
MyViewBean.java
#ViewScoped
#Named
public class MyViewBean implements Serializable {
private Component component;
public Component getComponent() {
return component;
}
public void setComponent(Component component) {
this.component = component;
}
public String increment(){
component.setCounter(component.getCounter()+1);
return "";
}
}
Component.java
#FacesComponent(value = "composite")
public class Component extends UINamingContainer {
private Integer counter = 0;
public Integer getCounter() {
return counter;
}
public void setCounter(Integer counter) {
this.counter = counter;
}
}
compositeTest.xhtml
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:h="http://xmlns.jcp.org/jsf/html"
template="/WEB-INF/templates/default.xhtml"
xmlns:pelda="http://xmlns.jcp.org/jsf/composite/component">
<ui:define name="content">
<h1>Composite component Test!</h1>
<h:form>
<pelda:composite binding="#{myViewBean.component}" />
<h:commandButton action="#{myViewBean.increment()}" value="Push me!"/>
</h:form>
</ui:define>
</ui:composition>
composite.xhtml
<cc:interface componentType="composite">
</cc:interface>
<cc:implementation>
<h:outputText id="id_hello" value="Helloka" />
<h:outputText id="id_counter" value="#{cc.counter}" />
</cc:implementation>
</html>
How to achieve that the counter can be incremented (with #RequestScoped bean it resets) and won't fail with idUniqueness error? We're using Mojarra 2.2.8 (Default in wildfly), also tried with Mojarra 2.2.12 (the latest as per writing this).
Thanks in advance!
UIComponent instances are inherently request scoped. You should never reference UIComponent instances beyond the request scope. Carefully read How does the 'binding' attribute work in JSF? When and how should it be used? for an elaborate explanation on that.
You only want to save its state in the JSF state via the inherited getStateHelper() method. This acts basically as the view scope.
#FacesComponent(value = "composite")
public class Component extends UINamingContainer {
public Integer getCounter() {
return (Integer) getStateHelper().eval("counter", 0);
}
public void setCounter(Integer counter) {
getStateHelper().put("counter", counter);
}
}
Don't forget to get rid of the binding attribute in the view.
See also:
How to save state when extending UIComponentBase
I need your help is solving the error in the log. In my jsp, I am having selectmanycheckbox:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<%# page deferredSyntaxAllowedAsLiteral="true" %>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core">
<h:form>
<h:selectManyCheckbox value="#{com.favoriteCar2}">
<f:selectItems value="#{com.favoriteCar2Value}" />
</h:selectManyCheckbox>
<br/>
<h:selectManyCheckbox value="#{com.favoriteCar3}">
<f:selectItems value="#{com.favoriteCar3Value}" />
</h:selectManyCheckbox>
<h:commandButton value="Submit" action="results" />
<h:commandButton value="Reset" type="reset" />
</h:form>
and mybean:
import java.io.Serializable;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.Map;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
#ManagedBean
#SessionScoped
public class com implements Serializable{
private static final long serialVersionUID = 7134492943336358840L;
public String[] favoriteCar1;
public String[] favoriteCar2;
public String[] favoriteCar3;
public String[] favoriteCar4;
public String[] getFavoriteCar2Value()
{
favoriteCar2 = new String [5];
favoriteCar2[0] = "116";
favoriteCar2[1] = "118";
favoriteCar2[2] = "X1";
favoriteCar2[3] = "Series 1 Coupe";
favoriteCar2[4] = "120";
return favoriteCar2;
}
public String getFavoriteCar2InString()
{
return Arrays.toString(favoriteCar2);
}
private static Map<String, Object> car3Value;
static
{
car3Value = new LinkedHashMap<String, Object>();
car3Value.put("Car3 - 316", "BMW 316");
car3Value.put("Car3 - 318", "BMW 318");
car3Value.put("Car3 - 320", "BMW 320");
car3Value.put("Car3 - 325", "BMW 325");
car3Value.put("Car3 - 330", "BMW 330");
}
public Map<String, Object> getFavoriteCar3Value()
{
return car3Value;
}
public String getFavoriteCar3InString() {
return Arrays.toString(favoriteCar3);
}
}
The log is showing the error and no checkbox is shown in the jsp:
java.lang.IllegalArgumentException: Expected a child component type of UISelectItem/UISelectItems for component type javax.faces.SelectMany(j_id_id2). Found [Ljava.lang.String
Even I tried static children and it is not populating them.
So can you please help
It's because your SelectItems value is a String[], see the java docs regarding the value attribute of SelectItems in JSF 1.2 :
Value binding expression pointing at a List or array of SelectItem
instances containing the information for these options.
You are also returning the value of your selectManyCheckbox in the SelectItems which doesn't make sense, you should better learn more about how to use SelectItems. You can find many examples in the selectOneMenu wiki page which is very similar to the selectManyCheckbox, Or in The Java EE 6 Tutorial (Note that this links are JSF 2.0 but that may help you to understand the concept).
Regarding your example, that should be something like this:
private List<SelectItem> favoriteCar2Value;
// (we will add only a getter, setter is not necessary)
public List<SelectItem> getFavoriteCar2Value() {
favoriteCar2Value = new ArrayList<SelectItem>();
favoriteCar2Value.add(new SelectItem("116", "116 label"));
favoriteCar2Value.add(new SelectItem("118", "118 label"));
favoriteCar2Value.add(new SelectItem("X1", "X1 label"));
favoriteCar2Value.add(new SelectItem("Series 1 Coupe", "Series 1 Coupe label"));
favoriteCar2Value.add(new SelectItem("120", "120 label"));
return favoriteCar2Value;
}
Finnaly, maybe it's time for you to consider migrating to JSF 2.0 which may let you working with facelets instead of JSP, benefit from Ajax support... For a clear comparative see: What are the main disadvantages of Java Server Faces 2.0?
I am using PrimeFaces and I need auto filter functionality in the drop down control.
My requirement is that as I start typing, the drop down list should be filtered to show only the items that match with the entered characters.
I am currently using AutoComplete control and as you can see in the image below, it does NOT do the filtering, but only highlights the entered characters in bold. Is there any property of this control that will help me do this out of the box or do I have to implement it myself? If so, how to do the same?
Here is the code:
<p:autoComplete id="state" label="state" completeMethod="#{patientBean.listStates}" required="true" dropdown="true" forceSelection="TRUE"/>
Or, is there any other control that will help me achieve this out of the box?
By the way, I am not sure if the following property of AutoComplete control is relevant to this by any chance? Snippet from the PrimeFaces documentation given below:
autocomplete null String Controls browser autocomplete behavior.
UPDATE
I am using:
JSF 2.1.6
PrimeFaces 4.0
Code
test.xhtml
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui">
<h:head>
<title><ui:insert name="title">Test</ui:insert></title>
</h:head>
<h:body>
<h:form id="createPatientForm">
<h:panelGrid columns="2">
<p:outputLabel value="State*"></p:outputLabel>
<p:autoComplete id="state" label="State" completeMethod="#{stateBean.listStates}" required="true" dropdown="true" forceSelection="TRUE"/>
</h:panelGrid>
</h:form>
</h:body>
</html>
StateBean.java
import java.util.ArrayList;
import java.util.List;
import javax.faces.bean.ManagedBean;
#ManagedBean
public class StateBean {
private String state;
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
public List<String> listStates(String district) {
List<String> cities = new ArrayList<String>();
cities.add("California");
cities.add("New Jersey");
cities.add("Texas");
return cities;
}
}
Please checkout SelectOneMenuFilter.
http://blog.primefaces.org/?p=2097
I know that there is an accepted answer already but I still want to give an answer to the problem with "Autocomplete"-control! It is possible to solve the problem with it and I think the autocomplete-control in some cases is better than the "SelectOneMenuFilter".
You just need to change your "listStates" method to do what you want! Right now your code did exactly what you told him to do! It created a list and put it into your autocomplete-control.
To get your desired result you need to change it accordingly like this:
public List<String> listStates(String district) {
List<String> tempList = new ArrayList<String>();
List<String> cities = new ArrayList<String>();
cities.add("California");
cities.add("New Jersey");
cities.add("Texas");
for (String value : cities) {
if (value.toLowerCase().contains(district.toLowerCase())) {
tempList.add(value);
}
}
return tempList;
}
This is my xhtml:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core">
<h:head>
<title>Keep alive</title>
</h:head>
<f:metadata>
<f:viewParam name="value" id="value" value="#{myBean.val}" ></f:viewParam>
</f:metadata>
<h:body>
Hello.<h:form><h:outputLabel value="#{myBean.val}"></h:outputLabel></h:form>
</h:body>
</html>
And this is my bean:
import javax.faces.bean.RequestScoped;
import javax.faces.bean.ManagedBean;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
#RequestScoped
#ManagedBean
public class MyBean {
#PersistenceContext(unitName = "myPUhere")
private EntityManager em;
/**
* Creates a new instance of myBean
*/
public MyBean() {
System.out.println("mybeanload");
if (getWaarde() == "yes") {
System.out.println("IT WORKS!!");
}
}
private String val;
public String getVal() {
System.out.println("getting value");
return val;
}
public void setVal(String value) {
System.out.println("setting value to " + value);
this.val = value;
}
}
My Bean does not respond to this, what don't I see here? It does not display the value I enter in the URL, nor it displays my outputLabel.
So, you're retrieving the raw JSF source code in the browser instead of its generated HTML output. Browsers obviously don't understand JSF code (like as it doesn't understand JSP/PHP/ASP/etc code), but it only understands HTML code. This can happen when the FacesServlet hasn't been invoked, it's namely the one responsible for all the JSF works.
Perhaps your FacesServlet is based on some tutorial or IDE-autogenerated code been mapped on an URL pattern different than *.xhtml, such as *.jsf or *.faces. In that case, you've 2 options:
Fix the request URL in your browser's address bar to match exactly that URL pattern. So, assuming that it's *.jsf, then don't open the page by
http://localhost:8080/context/index.xhtml
but instead by
http://localhost:8080/context/index.jsf
Fix the URL pattern to be *.xhtml directly. This wasn't possible back in JSF 1.x as the FacesServlet would otherwise call itself in an infinite loop, but this is quite possible in JSF 2.x and a lot of books/tutorials/resources/IDEs didn't take this into account.
<url-pattern>*.xhtml</url-pattern>
See also:
JSF Facelets: Sometimes I see the URL is .jsf and sometimes .xhtml. Why?
I have the following problem. When I click the button "Enviar", this calls another method that is associated to a selectOneMenu (in the attribute
valueChangeListener called "validarSelect"), and later, calls the method that this button has associated in the attribute actionListener called "validarBoton".
I wonder, why this happens. I expect the valueChangeListener to be not called since I have not changed the dropdown.
This is my page JSF:
<?xml version='1.0' encoding='windows-1252'?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<f:view xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html">
<html xmlns="http://www.w3.org/1999/xhtml">
<h:head></h:head>
<h:body>
<h:form>
<h:commandButton value="Enviar..." id="validar" actionListener="#{Domiciliacion.validarBoton}"/>
<h:selectOneMenu valueChangeListener="#{Domiciliacion.validarSelect}"
binding="#{Domiciliacion.selectCombo}">
<f:selectItems value="#{Domiciliacion.lista}"/>
<f:ajax event="valueChange" render="#this"/>
</h:selectOneMenu>
</h:form>
</h:body>
</html>
And this, is the ManagedBean:
package domiciliaciontest;
import java.util.ArrayList;
import java.util.List;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.component.html.HtmlSelectOneMenu;
import javax.faces.event.ActionEvent;
import javax.faces.event.ValueChangeEvent;
#ManagedBean(name = "Domiciliacion")
#ViewScoped
public class MB0001 {
private HtmlSelectOneMenu selectCombo;
private List<String> lista = new ArrayList<String>();
public MB0001() {
super();
System.out.println("Entro al constructor...");
lista.add("Caracas");
lista.add("Bogota");
lista.add("Santiago");
}
public void validarBoton(ActionEvent actionEvent) {
System.out.println("Entro a validarBoton...");
// Add event code here...
}
public void validarSelect(ValueChangeEvent valueChangeEvent) {
// Add event code here...
System.out.println("Entro a validarSelect...");
}
public void setSelectCombo(HtmlSelectOneMenu selectCombo) {
this.selectCombo = selectCombo;
}
public HtmlSelectOneMenu getSelectCombo() {
return selectCombo;
}
public void setLista(List<String> lista) {
this.lista = lista;
}
public List<String> getLista() {
return lista;
}
}
this is the output when I click the button "Enviar":
Entro a validarSelect...
Entro a validarBoton...
The valueChangeListener method will be invoked when the submitted value is different from the initial value, regardless of whether you have changed it yourself or not. So, if the currently submitted value (which is "Caracas" in your case) is different from the initial value (which is null in your case), then the valueChangeListener method will be invoked.
See also:
When to use valueChangeListener or f:ajax listener?
Best way to add a "nothing selected" option to a selectOneMenu in JSF
Unrelated to the concrete problem, seeing this in combination with binding attribute gives me the impression that you're trying to achieve something which you've read in an article or answer targeted on JSF 1.x. This is namely recognizeable as part of a hack to populate child dropdowns in JSF 1.x. You do not need this approach for JSF 2.x. Further, your method names with "validar" ("validate") are misleading. Don't you actually need a fullworthy Validator? But as said, that's a different problem.
See also:
Make multiple dependent / cascading selectOneMenu dropdown lists in JSF