How to generate primefaces PickList component programmatically? - jsf

public void populateForm(ComponentSystemEvent event) {
HtmlForm form = (HtmlForm) event.getComponent();
List<String> citiesSource = new ArrayList<String>();
List<String> citiesTarget = new ArrayList<String>();
citiesSource.add("San Francisco");
citiesSource.add("London");
citiesSource.add("Paris");
citiesSource.add("Istanbul");
citiesSource.add("Berlin");
citiesSource.add("Barcelona");
citiesSource.add("Rome");
cities = new DualListModel<String>(citiesSource, citiesTarget);
PickList pickList = new PickList();
pickList.setId("pickList");
pickList.setValue(cities);
pickList.setVar("cities");
pickList.setItemLabel(pickList.getVar());
pickList.setItemValue(cities);
form.getChildren().add(pickList);
}
This was my approach, and output I got is:
But if I add <p:pickList id="pickList" value="#{bean.cities}" var="cities" itemLabel="#{cities}" itemValue="#{cities}" /> in my xhtml, I get this output:
What is going on here?

This is how I solved the PickList issue:
FacesContext context = FacesContext.getCurrentInstance();
ExpressionFactory ef = context.getApplication().getExpressionFactory();
PickList pickList = new PickList();
ValueExpression pickListValue = ef.createValueExpression(
context.getELContext(), "#{ruleManagedBean.cities}",DualListModel.class);
ValueExpression pickListVar = ef.createValueExpression(
context.getELContext(), "cities", String.class);
ValueExpression pickListItemLabel = ef.createValueExpression(
context.getELContext(), "#{cities}", String.class);
ValueExpression pickListItemValue = ef.createValueExpression(
context.getELContext(), "#{cities}", String.class);
pickList.setId("pickList");
pickList.setValueExpression("value", pickListValue);
pickList.setValueExpression("var", pickListVar);
pickList.setValueExpression("itemLabel", pickListItemLabel);
pickList.setValueExpression("itemValue", pickListItemValue);
form.getChildren().add(pickList);
Note: ruleManagedBean.cities refers to the DualListModel, populated as
List<String> citiesSource = new ArrayList<String>();
List<String> citiesTarget = new ArrayList<String>();
citiesSource.add("San Francisco");
citiesSource.add("London");
citiesSource.add("Paris");
citiesSource.add("Istanbul");
citiesSource.add("Berlin");
citiesSource.add("Barcelona");
citiesSource.add("Rome");
cities.setSource(citiesSource);
cities.setTarget(citiesTarget);
Make sure that you have declared this DualListModel globally as below and has getter setter methods
private DualListModel<String> cities = new DualListModel<String>();

Instead of PickList pickList = new PickList(); try this:
Application application = FacesContext.getCurrentInstance().getApplication();
PickList pickList = (PickList) application.createComponent(PickList.COMPONENT_TYPE);
Change your pickList.setValue(cities); for this:
Note: cities must be a field on your bean with its own getter.
ExpressionFactory ef = application.getExpressionFactory();
ELContext elc = FacesContext.getCurrentInstance().getELContext();
ValueExpression value = ef.createValueExpression(elc, "#{bean.cities}", DualListModel.class);
pickList.setValueExpression("value", value);

Related

primefaces value expression on DefaultMenuItem

Hi i trying to set value expresion on some attribute (for example attribute class) of DefaultMenuItem of Primefaces. Something like:
<p:menuitem class="#{view.viewId.endsWith('index.xhtml') ? 'menuitm-hovered' : ''}" value="Home" url="/" />
exaclty these peace
class="#{view.viewId.endsWith('index.xhtml') ? 'menuitm-hovered' : ''}"
but programaticaly. On bean should be something like these:
menuItem.setValueExpression("class", Helper2.createValueExpression("#{view.viewId.endsWith('index.xhtml') ? 'menuitm-hovered' : ''}", Object.class));
DefaultMenuItem dosent have setValueExpression method so im stuck and I dont know how i could do that. If someone could help i will be grateful for help.
As far as i know setValueExpression can be done in GraphicImage (in these case with value attribute)
GraphicImage image = new GraphicImage();
image.setValueExpression("value", Helper2.createValueExpression("#{position.images.link}", Object.class));
Below static method of Helper2 class:
public static ValueExpression createValueExpression(String expression, Class clazz) {
FacesContext fc = FacesContext.getCurrentInstance();
ELContext elContext = fc.getELContext();
ExpressionFactory expFactory = fc.getApplication().getExpressionFactory();
ValueExpression ret = expFactory.createValueExpression(elContext, expression, clazz);
return ret;
}
Try this:
MenuButton menuButton = new MenuButton();
item = new UIMenuItem();
item.setValue(command.getLabel());
item.setActionExpression(Utility.createMethodExp(command.getCommandExpression()));
item.setValueExpression("disabled", Utility.createExpression(command.getDisabledExpression(), Boolean.class));
menuButton.getChildren().add(item);
where Utility.createMethodExpression is a static method (of my class Utility):
public static MethodExpression createMethodExp(String stringExpression) {
FacesContext context = FacesContext.getCurrentInstance();
return context.getApplication().getExpressionFactory().createMethodExpression(Utility.getELContext(),
stringExpression, Void.class, new Class[] {});
}
and Utility.createExpression is
public static ValueExpression createExpression(String stringExpression, Class<?> type) {
FacesContext context = FacesContext.getCurrentInstance();
return context.getApplication().getExpressionFactory().createValueExpression(context.getELContext(),
stringExpression, type);
}

JSF CDI #Named + isAnnotationPresent + #CustomSecurityAnnotation

I'm using a custom annotation security as described in this link. I'm upgrading my jsf managed beans from #ManagedBean to #Named (CDI). Since the CDI does not support the scope #ViewScoped, i'm using org.omnifaces.cdi.ViewScoped. However, in this case, this check fails if method.isAnnotationPresent(Permissao.class){}. How should I adapt my security check to use with CDI + ViewScoped from Omnifaces?
Edit
Using #ManagedBean/ViewScoped(jsf) instead of #Named/ViewScoped(cdi + omnifaces) works.
The problem occurs in this line if (metodo.isAnnotationPresent(Permissao.class)) {}
public void verificaPermissaoAcesso(ActionEvent event) {
final FacesContext facesContext = FacesContext.getCurrentInstance();
UIComponent source = event.getComponent();
ActionSource2 actionSource = (ActionSource2) source;
MethodExpression methodExpression = actionSource.getActionExpression();
String expressao = methodExpression.getExpressionString(); // #{nomeManagedBean.nomeMetodo(param)}
String nomeManagedBean = expressao.substring(0, expressao.indexOf('.')).substring(2);
String nomeMetodoComParenteses = expressao.substring(expressao.indexOf('.') + 1);
String nomeMetodo = nomeMetodoComParenteses.substring(0, nomeMetodoComParenteses.indexOf("("));
ELContext elContext = facesContext.getELContext();
ExpressionFactory factory = facesContext.getApplication().getExpressionFactory();
ValueExpression ve = factory.createValueExpression(elContext, "#{" + nomeManagedBean + '}', Object.class);
//Object jsfManagedBean = ve.getValue(elContext);
Context ctx = bm.getContext(org.omnifaces.cdi.ViewScoped.class);
Bean bean = bm.resolve(bm.getBeans(nomeManagedBean));
Object jsfManagedBeanProxy = ctx.get(bean);
List<Method> listaMetodos = Arrays.asList(jsfManagedBeanProxy.getClass().getMethods());
for (Method metodo : listaMetodos) {
if (nomeMetodo.equals(metodo.getName())) {
if (metodo.isAnnotationPresent(Permissao.class)) {
Permissao anotacaoSeguranca = metodo.getAnnotation(Permissao.class);
SegurancaUtil.verificar(anotacaoSeguranca.acoes());
break;
}
}
}
}
My annotation class
#Documented
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
public #interface Permissao {
String[] acoes();
}
My annotated method in jsf managed bean
#Permissao(acoes={"permission1", "permission2"})
public void myMethod(long id) {}
Edit 2 - Solution by #meriton
Context ctx = bm.getContext(org.omnifaces.cdi.ViewScoped.class);
Bean bean = bm.resolve(bm.getBeans(nomeManagedBean));
Object jsfManagedBeanProxy = ctx.get(bean);
CDI doesn't inject a naked CDI bean as a dependency, but a proxy that redirects to the contextual object of the active scope. This proxy class does not have your annotation.
See https://issues.jboss.org/browse/CDI-10 for how to unwrap the proxy.

add event in dynamic component created in the bean jsf

Good day, so guys, what I'm wanting to do is the following, I add a HtmlSelectOneMenu via bean in JSF page, and like it when the guy changed his value, HtmlSelectOneMenu him to add another, add the HtmlSelectOneMenu'm getting no problem, however like to know how do I add an event to them via BEAN course ehehee
HtmlSelectOneMenu select = new HtmlSelectOneMenu();
HtmlOutputLabel lblData = new HtmlOutputLabel();
lblData.setValue(list.get(contador).getItem().getNome());
UISelectItem item = new UISelectItem();
item.setItemLabel("NÃO");
item.setItemValue(false);
UISelectItem item2 = new UISelectItem();
item2.setItemLabel("SIM");
item2.setItemValue(true);
select.getChildren().add(item);
select.getChildren().add(item2);
FacesContext context = FacesContext.getCurrentInstance();
ELContext elContext = context.getELContext();
Application app = context.getApplication();
ExpressionFactory expressionFactory = app.getExpressionFactory();
ValueExpression ve = expressionFactory.createValueExpression(elContext, "#{projetoBean.qualRespondeu}", String.class);
select.setValueExpression("valeu", ve);
UIPanel container = (UIPanel) FacesContext.getCurrentInstance().getViewRoot().findComponent(":formProjeto:painel");
container.getChildren().add(lblData);
container.getChildren().add(select);
contador++;
Thanks for answers Kolossus however, decided as follows:
AjaxBehavior ajax = new AjaxBehavior();
ajax.setAsync(true);
ajax.setUpdate(":formProjeto");
MethodExpression ex = expressionFactory.createMethodExpression(elContext, "#{projetoBean.adicionaPergunta()}", null, new Class[]{});
ajax.addAjaxBehaviorListener(new AjaxBehaviorListenerImpl(ex, ex));
select.addClientBehavior("change", ajax);
Try the following steps:
Create the AjaxBehaviorListener (the actual processing of the event):
MyAjaxBehaviorListener implements AjaxBehaviorListener{
#Override
public void processAjaxBehavior(AjaxBehaviorEvent e) throws AbortProcessingException {
//perform the event processing here
}
}
Attach the listener to an AjaxBehavior
AjaxBehavior ajaxBehavior = (AjaxBehavior) FacesContext.getCurrentInstance().getApplication() .createBehavior(AjaxBehavior.BEHAVIOR_ID);
MyAjaxBehaviorListener listener = new MyAjaxBehaviorListener();
ajaxBehavior.setExecute(Collections.singletonList("#this")); //sets the execute attribute of the event handler
ajaxBehavior.addAjaxBehaviorListener(listener);
Attach the AjaxBehavior to the component
item.addClientBehavior("change",ajaxBehavior); //set the triggering event to "change"

How to add SetPropertyActionListener correctly?

i use Primefaces 3.0.1 and build up a menubar with programmatically filled model. I need some Links like depotDetails.xhtml?id=1 But if i use these URL for my menuitem
item.setUrl("depotDetail.xhtml?id=1"); // that dont work
so i tried to add an ActionListener:
FacesContext facesContext = FacesContext.getCurrentInstance();
ValueExpression target = facesContext.getApplication().getExpressionFactory().createValueExpression(FacesContext.getCurrentInstance().getELContext(), "#{DepotBean.currentDepot}",String.class);
ValueExpression value = facesContext.getApplication().getExpressionFactory().createValueExpression(FacesContext.getCurrentInstance().getELContext(), "ehnemeneee",String.class);
ActionListener handler = new SetPropertyActionListenerImpl(target, value);
item.addActionListener(handler);
but that also dont work. Can anybody help?
Greets Thomas
I got a solution ... but is it the right way?
// building the menu model ..
UIParameter param = null;
for(Depots testdepot: depotList){
param = new UIParameter();
param.setName("currentDepotId");
param.setValue(testdepot.getIdDepot());
item = new MenuItem();
item.setValue(testdepot.getDepotName());
// calling menuListener
item.addActionListener(new MenuListener());
item.setUpdate("messages");
item.setId("menuItemDepot"+testdepot.getIdDepot());
item.getChildren().add(param);
submenu.getChildren().add(item);
}
// MenuListener
public void processAction(ActionEvent event) throws AbortProcessingException {
FacesContext fc = FacesContext.getCurrentInstance();
HttpServletRequest request = (HttpServletRequest) fc.getExternalContext().getRequest();
HttpSession session = (HttpSession) fc.getExternalContext().getSession(false);
// get param id
String name = (String) event.getComponent().getAttributes().get("currentDepotId");
// set session var
session.setAttribute("currentDepotId", name);
fc.getExternalContext().redirect(request.getContextPath() + "/userarea/depotDetail.xhtml");
}
// read the session in the depot bean
FacesContext fc = FacesContext.getCurrentInstance();
HttpSession session = (HttpSession) fc.getExternalContext().getSession(false);
String currentDepotId = session.getAttribute("currentDepotId");

Programmatically get expression value of facelets parameter (variable)

Following java code allows to access any object or variable from faces context:
ELContext elCtx = facesContext.getELContext();
ExpressionFactory exprFac = facesContext.getApplication().getExpressionFactory();
MyProperty myProperty = (MyProperty) exprFac.createValueExpression(elCtx, "#{somebean.someattr.someproperty}", MyProperty.class).getValue(elCtx);
I use the code from within my custom converter to read additional converting parameters from context.
The code works correctly if #{somebean} is defined as normal backing bean within JSF context.
Facelets allow to create 'shortcut' to JSF expressions. Example:
<ui:param name="shortcut" value="#{somebean.someattr.someproperty}" />
<div>#{somebean.someattr.someproperty} equals #{shortcut}</div>
In this case both #{somebean.someattr.someproperty} and #{shortcut} have the same value.
However these 'shortcut' names are not accessible using java code above. For example:
MyProperty myProperty1 = (MyProperty) exprFac.createValueExpression(elCtx, "#{somebean.someattr.someproperty}", MyProperty.class).getValue(elCtx);
// myProperty1 has expected value
MyProperty myProperty2 = (MyProperty) exprFac.createValueExpression(elCtx, "#{shortcut}", MyProperty.class).getValue(elCtx);
// myProperty2 is null
Is there a way to access a facelets context and to read 'shortcut' parameter values, defined on the current JSF page?
I had the same problem and have chosen the following approach:
/**
* Führt eine Expression im aktuellen Faces EL Context
* UND im Facelets El Context aus.
*
* #param facesContext
* #param expression
* #return object
*/
private static Object executeExpressionInUIContext (final FacesContext facesContext, final String expression) {
final ELContext elContext = facesContext.getELContext();
final Application application = facesContext.getApplication();
Object result = executeExpressionInElContext(application, elContext, expression);
if (null == result) {
FaceletContext faceletElContext = (FaceletContext) FacesContext.getCurrentInstance().getAttributes().get(FaceletContext.FACELET_CONTEXT_KEY);
result = executeExpressionInElContext(application, faceletElContext, expression);
}
return result;
}
private static Object executeExpressionInElContext (Application application, ELContext elContext, String expression) {
ExpressionFactory expressionFactory = application.getExpressionFactory();
ValueExpression exp = expressionFactory.createValueExpression(elContext, expression, Object.class);
return exp.getValue(elContext);
}
"ui:param" is part of the Facelet view handling technology. Facelets extends JSF.
Both technologies use their own Context when storing variables.
Beside the Faces El Context there is a Facelet El Context (FaceletContext).
The stated method evaluates expressions in both contexts. Be aware that this will not work if two values are stored under the same name in each context.
It seems that facelet shortcuts do not exist in the context, where I try to access them.
I have made following workaround: On JSF page where my input element is placed, I have added a <f:param> element as child of the input with my converter.
<h:inputText id="myid" value="#{action.myinput}">
<f:converter converterId="myConverter" />
<f:param name="converterParameters" shortcut="#{somebean.someattr.someproperty}"/>
</h:inputText>
Then in converter I'm able to find UIParam element as one of the input children and read my shortcuts from it.
public Object getAsObject(FacesContext context, UIComponent component, String value) {
MyProperty myProperty = null;
try {
for (final UIComponent child : component.getChildren()) {
if ("converterParameters".equals(child.getAttributes().get("name"))) {
final ELContext elCtx = context.getELContext();
myProperty = (MyProperty) child.getValueExpression("shortcut").getValue(elCtx);
break;
}
}
if (myProperty == null) {
throw new NullPointerException("My property is undefined.");
}
} catch (Exception e) {
LOG.error("Cannot convert " + value + ". Use <f:param name=\"converterParameters\" "
+ "shortcut=\"#{here.comes.shortcut}\"/> for your input element. ", e);
throw new ConverterException("Cannot initialize converter.", e);
}
//...
}
The mapping of ui:param is not stored in context, it's in the VariableMapper of each individual ValueExpression.
So if you need to create ValueExpression programmatically, relying on another ValueExpression's varMapper, you can do something like this:
VariableMapper varMapper = new DefaultVariableMapper();
varMapper.setVariable(mappingName, component.getValueExpression(mappedAttributeName));
return new ValueExpressionImpl(expression, null, null, varMapper, expectedType);

Resources