Dynamically created input components do not show model values - jsf

I have some fields of a bean that I need to show programmatically. Is something like this:
HtmlPanelGrid panel = new HtmlPanelGrid();
panel.setColumns(4);
HtmlOutputLabel fieldOut = new HtmlOutputLabel();
fieldOut.setId("fieldOutId");
fieldOut.setValue("name");
panel.getChildren().add(fieldOut);
HtmlInputText fieldIn = new HtmlInputText();
fieldIn.setId("fieldInId");
fieldIn.setPartialSubmit(true);
fieldIn.setValueExpression(
"field", UtilFaces.createValueExpression("#{newElementBean.fieldName}",String.class));
panel.getChildren().add(fieldIn);
mainForm.getChildren().add(panel);
In newElements.xhtml i've defined a form which is binded to mainForm, in this way:
<ice:form binding="#{newElementBean.mainForm}">
<ice:inputText id="ANOTHERFIELD" value="#{newElementBean.anotherField}"/>
<ice:commandButton action="#{newElementBean.save}" value="Save"/>
</ice:form>
When I click on the save button and I go to the next view, the field "ANOTHERFIELD" has taken the value from the bean, and shows up correctly, but the fields that were dinamically generated shows empty. Its values in the backing bean also are null. It's like the ValueExpression is not working for the HtmlInputText that I created in the backing bean. I'm using Icefaces 3.3 with Mojarra 2.1.17.
How is this caused and how can I solve it?

I solved it. I made two mistakes:
The proper setValueExpression call is like this:
fieldIn.setValueExpression("value", UtilFaces.createValueExpression("#newElementBean.fieldName}");
I was incorrectly using "field1" as 1st argument instead of "value".
This is not visble in the question, but my createValueExpression() helper method was also wrong. The following is working for me:
public static ValueExpression createValueExpression(String expression) {
Application app = FacesContext.getCurrentInstance().getApplication();
ExpressionFactory elFactory = app.getExpressionFactory();
ELContext elContext = FacesContext.getCurrentInstance().getELContext();
return elFactory.createValueExpression(elContext, expression, Object.class);
}

Related

MethodExpression not firing in HtmlCommandLink

I have a dynamically generated Datatable, like this
DataTable dataTable = new DataTable();
dataTable.setValue(relatorioVOList);
dataTable.setVar("rVO");
Column checkBoxColumn = new Column();
checkBoxColumn.getChildren().add(this.viewComponentBuilder.createExpressionTextWithLink("#{rVO.iRelatorio}","#{rVO.nNome}"));
dataTable.getColumns().add(checkBoxColumn);
public HtmlForm createExpressionTextWithLink(String iRelatorioExpressionValue, String valueExpressionValue) {
HtmlForm form = new HtmlForm();
HtmlCommandLink link = new HtmlCommandLink();
//config
FacesContext context = FacesContext.getCurrentInstance();
Application application = context.getApplication();
ExpressionFactory ef = application.getExpressionFactory();
ELContext elc = context.getELContext();
//value that is the reports name
ValueExpression nameValueExp = ef.createValueExpression(elc, valueExpressionValue, Object.class);
link.setValueExpression("value", nameValueExp);
//action that goes to method teste when link is clicked
MethodExpression methodExpression = createMethodExpression("#{componenteC.teste(rVO.iRelatorio)}", String.class, Integer.class);
link.setActionExpression(methodExpression);
form.getChildren().add(link);
return form;
}
private static MethodExpression createMethodExpression(String expression, Class<?> returnType, Class<?>... parameterTypes) {
FacesContext facesContext = FacesContext.getCurrentInstance();
return facesContext.getApplication().getExpressionFactory().createMethodExpression(
facesContext.getELContext(), expression, returnType, parameterTypes);
}
In ComponenteC, a RequestScopedBean, the teste function
public String teste(Integer iRelatorio) {
System.out.println("cheguei");
return "componente";
}
The goal is that the teste function will generate an url according to the iRelatorio parameter.
The issue here is that the function is never called. I tried replacing the rVO.iRelatorio with an explicit 10, "#{componenteC.teste(10)}" and even then the action seems to not be fired.
The report name is displayed correctly.
Dynamically created UIInput, UICommand and UINamingContainer components must have a fixed id assigned. Otherwise it will get an autogenerated one which is not necessarily the same when the view is restored. The component ID is used in request parameter names in submitted form data, which JSF would then use to collect the submitted input values and identify the invoked commands during apply request values phase. If the component ID changes, then JSF won't be able to perform the apply request values phase as intented.
Thus, act accordingly:
dataTable.setId("tableId");
// ...
form.setId("formId");
// ...
link.setId("linkId");
There are other potential causes, but they are not visible in the information provided so far in the question. To cover that, take your time to carefully read the following related answers on "dynamically" creating components/views:
Create inputtext dynamically
How does the 'binding' attribute work in JSF? When and how should it be used?
How to create dynamic JSF form fields
That said, you're really better off using XHTML to declare and create components instead of all that Java code mess. XHTML(+XML) is much more declarative and readable and therefore better understandable and maintainable. JSTL may be very helpful in this all.

Programmatic creation of JSF components with EL expressions using EL functions throws javax.el.ELException: function not found

I'm programmatically creating the PrimeFaces <p:column>s for a <p:dataTable> using a so-called BaseColumnHandler. There's one column here that shows an icon or not, depending on some condition given by the row's entity (here 'event').
In JSF this would look something like this (inside a <p:dataTable ... var="event" ...>):
<p:column ...>
<p:graphicImage value="/resources/somePath/to/icon/whatever.png"
title="#{of:format1('{0} conflicts available', event.results.size())}"
style="#{event.whatEverVisibleCondition ? '' : 'visibility: hidden;'}"
... />
<p:graphicImage value="/resources/somePath/to/icon/whatsoever.png"
title="What so ever available"
style="#{event.whatSoEverVisibleCondition ? '' : 'visibility: hidden;'}"
... />
</p:column>
This simply shows a single info column where each row (event entity) displays an icon for an available feature or not (CSS visibility: hidden; replaces the JSF rendered attribute, because we need the icon space to be used in case of invisiblity so that icons will align).
Please assume the icon paths to be correct.
In the class building the icon column, I have the following lines:
#Named
#ViewScoped
public class MyColumnHandler
{
// get necessary instances to handle value expressions
FacesContext facesContext = FacesContext.getCurrentInstance();
ELContext elContext = facesContext.getELContext();
ExpressionFactory factory = facesContext.getApplication().getExpressionFactory();
#PostConstruct
public void buildColumns()
{
...
UIGraphic graphicImage = new GraphicImage();
this.setTitleExpressionToComponent(graphicImage, "#{of:format1('{0} conflicts available', event.results.size())}");
...
}
private void setTitleExpressionToComponent(UIComponent component, String expression)
{
// expression goes to "title" attribute and is of type String
component.setValueExpression("title", this.factory.createValueExpression(this.elContext, expression, String.class));
}
...
}
When I render the page however, I get something like this:
javax.el.ELException: Function 'of:format1' not found
at com.sun.el.lang.ExpressionBuilder.visit(ExpressionBuilder.java:254)
at com.sun.el.parser.SimpleNode.accept(SimpleNode.java:172)
at com.sun.el.lang.ExpressionBuilder.prepare(ExpressionBuilder.java:219)
at com.sun.el.lang.ExpressionBuilder.build(ExpressionBuilder.java:230)
at com.sun.el.lang.ExpressionBuilder.createValueExpression(ExpressionBuilder.java:273)
at com.sun.el.ExpressionFactoryImpl.createValueExpression(ExpressionFactoryImpl.java:98)
at org.jboss.weld.util.el.ForwardingExpressionFactory.createValueExpression(ForwardingExpressionFactory.java:49)
at org.jboss.weld.el.WeldExpressionFactory.createValueExpression(WeldExpressionFactory.java:50)
at com.company.ci.common.view.framework.columnhandling.MyColumnHandler.setTitleExpressionToComponent(MyColumnHandler.java:121)
Obviously, the EL cannot find the OmniFaces function format1.
I have however added xmlns:of="http://omnifaces.org/functions" to every file that I can think of that is being used on the page that causes the exception.
Q:
What do I have to do to make the OmniFaces of:format1 function available, so that the exception isn't thrown? (hopefully a solution that doesn't require me to replace some ELContext with a custom class... if possible at all)
Thanks

Submitting programmatically created jsf form

I have created jsf form at backing bean. I have created form, it is being shown on screen with values successfully. When I click sumbit button, backing bean method is invoked with ActionEvent but updated input values are not submitted to backend. Backign bean entity object values are not updated.
Is there any wrong? Thanks so much for your helps,
Br.
Ramazan
HtmlForm form = new HtmlForm();
form.setId(appletWrapper.getName()+"_FORM");
PanelGrid panelGrid = (PanelGrid)createComponent(PanelGrid.COMPONENT_TYPE);
form.getChildren().add(panelGrid);
panelGrid.setColumns(4);
panelGrid.setId(appletWrapper.getName()+"_FORM_PANEL");
for (FieldWrapper fieldWrapper : appletWrapper.getFields()) {
panelGrid.getChildren().add(new UIFieldLabel(fieldWrapper).component(entities));
panelGrid.getChildren().add(newFieldComponent(fieldWrapper, entities));
}
HtmlPanelGroup panelGroup = new HtmlPanelGroup();
panelGroup.setId(appletWrapper.getName()+"_PANEL_GROUP");
panelGrid.getFacets().put("footer", panelGroup);
CommandButton commandButton = new CommandButton();
panelGroup.getChildren().add(commandButton);
commandButton.setId(appletWrapper.getName()+"_UPDATE");
commandButton.setAjax(true);
commandButton.setValue("update");
commandButton.setProcess("#this");
commandButton.setType("submit");
MethodExpression updateEntityME = createMethodExpression("#{mainBean.entityUpdateListener}", null, new Class[] {ActionEvent.class });
commandButton.addActionListener(new MethodExpressionActionListener(updateEntityME));
return form;
Edited: I gave all components a fixed id.
One of my coponents genarated like that;
InputText inputText = (InputText)createComponent(InputText.COMPONENT_TYPE);
inputText.setId(fieldAlphanumericWrapper.getName());
inputText.setValueExpression("value", createValueExpression("#{mainBean.selection."+fieldAlphanumericWrapper.getProperty()+"}", Object.class));
return inputText;
My backing bean target method;
public void entityUpdateListener(ActionEvent actionEvent) {
TAccount tAccount = (TAccount)getSelection();
System.out.println("tAccount.gettWebsite():"+tAccount.gettWebsite());
}
The main problem is that actually; When I press commandButton mainBean.setSelection is not invoked, so backing bean object is not updated. I cant take updated object instance through actionEvent instance.
I found solution, cause of problem was this line;
commandButton.setProcess("#this");
I have changed to this and problem solved.
commandButton.setProcess("#form");
Br.
Ramazan

JSF commandButton not working when created dynamically with java

Using primeFaces I have the following button:
<p:commandButton value="Submit" action="#{createDeal.saveDeal}" update="myPanel" />
This works just fine. However I want to generate that button using java.
I have the following code:
CommandButton submit = new CommandButton();
submit.setValue("Submit");
submit.setUpdate("myPanel");
FacesContext facesCtx = FacesContext.getCurrentInstance();
Application app = facesCtx.getApplication();
ExpressionFactory elFactory = app.getExpressionFactory();
ELContext elContext = facesCtx.getELContext();
MethodExpression methodExpression =null;
methodExpression = elFactory.createMethodExpression(elContext,"#{createDeal.saveDeal}",String.class, new Class[]{});
submit.addActionListener(new MethodExpressionActionListener(methodExpression));
submit.setActionExpression(methodExpression);
createButtons.getChildren().add(submit);
When I click submit, my form validates (which is done using the setRequired function on the input), but the form never hits my createDeal class. What am I doing wrong that the inline button works, but the java generated one does not.
One note. The button created inline using primefaces, is there on page load. The button attempted to be added with java is not done until after an Ajax call is made to generate both the form AND button.
Any assistance would be helpful.
Thanks.
Thanks to BalusC for all your help. I am still not sure how I missed this! The following works:
CommandButton submit = new CommandButton();
submit.setValue("Submit");
submit.setUpdate("myPanel");
submit.setId("create"+panelClass);
FacesContext facesCtx = FacesContext.getCurrentInstance();
ELContext elContext = facesCtx.getELContext();
Application app = facesCtx.getApplication();
ExpressionFactory elFactory = app.getExpressionFactory();
MethodExpression methodExpression =null;
methodExpression = elFactory.createMethodExpression(elContext,"# {createDeal.saveDeal}",null, new Class[]{});
submit.setActionExpression(methodExpression);
createButtons.getChildren().add(submit);
The null pointer exception was unrelated. It looks like simply adding the ID and removing the ActionListener did the trick. Much obliged!

JSF: How to attach an actionListener to component created programatically?

I have to create some commandLinks dynamically and attach some action listener to it, So I've put <h:panelGrid> on the JSP page and used such code to add the commandLinks and to assign action listeners to:
public ManagedBean(){
List<UIComponenet> child = panelGrid.getChilderen();
list.clear();
List<MyClass> myList = getSomeList();
for (MyClass myObj : myList){
FacesContext ctx = FacesContext.getCurrentContext();
HtmlCommandLink cmdLink = (HtmlCommandLink) ctx.getApplication.createComponent(HtmlCommandLink.COMPONENT_TYPE);
cmdLink.setValue(myObj.getName());
cmdLink.setActionLinstner(new ActionListener(){
public void processAction(ActionEvent event) throws AbortProcessingException{
System.out.println (">>>>>>>>>>>>>>>>>I am HERE ");
}
});
child.add(cmdLink);
}
}
But unfortunately, when I press this commandLinks, an exception thrown! How can I add component event listeners at runtime?
(Note, the code above my contain syntax/compilation errors as I just wrote).
First, you need to manually assign ID to any dynamically created UINamingContainer, UIInput and UICommand components. Otherwise JSF can't locate them in the component tree based on the request parameters, because it wouldn't match the autogenerated ID's.
Thus, at least do:
HtmlCommandLink link = new HtmlCommandLink();
link.setId("linkId");
// ...
Second, you're supposed to create an ActionListener as MethodExpression as follows:
FacesContext context = FacesContext.getCurrentInstance();
MethodExpression methodExpression = context.getApplication().getExpressionFactory().createMethodExpression(
context.getELContext(), "#{bean.actionListener}", null, new Class[] { ActionEvent.class });
link.addActionListener(new MethodExpressionActionListener(methodExpression));
// ...
...and of course have the following method in the backing bean class behind #{bean}:
public void actionListener(ActionEvent event) {
// ...
}
All the above dynamic stuff basically does the same as the following raw JSF tag:
<h:commandLink id="linkId" actionListener="#{bean.actionListener}" />
I had the same problem.
Transient components do not work with actionListeners.
Do not call
FacesContext.getCurrentInstance().getViewRoot().setTransient(true);
or
component.setTransient(true);
As soon as I removed it, it was OK.

Resources