Expand EL-Context for some value - jsf

Example in xhtml works, because #{row} is defined in p:dataTable. If I call getData not in context of p:dataTable it returns null. See Values.iterateOverDatatableValues for this situation where method returns null. How can I define row to use in my context. Possibly has datatable some functions to iterate over values so that #{row} will be defined?
Java:
#Named
#SessionScoped
class Test {
public Object getData () {
return Faces.evaluateExpressionGet("#{row.someProperty}"); //The String "#{row.someProperty}" comes from a collection.
}
}
XHTML #{row} is defined in Test.getData():
<p:dataTable value="#{bean.values}" var="row">
<p:column>
<h:outputText value="#{test.data}" />
</p:column>
</p:dataTable>
Java, #{row} is undefined:
class Values {
#Inject
Test test;
public void iterateOverDatatableValues (){
DataTable dt = Components.findComponent("datatableId");
for (Object o : dt.getValues()){
test.getData(); // <---- NULL because #{row} is not defined.
}
}
}

The solution was to use expressionFactory().createValueExperssion method.
private void setRowEL(Object o) {
ELContext elContext = Faces.getELContext();
ExpressionFactory expressionFactory = Faces.getApplication().getExpressionFactory();
ValueExpression aliasValueExpression = expressionFactory.createValueExpression(elContext, "#{row}", MyValue.class);
aliasValueExpression.setValue(elContext, o);
}

Related

Parameter in jsf bean is null. why?

I have a jsf page where i show a datatable. In the p:column tag i want to set the background-Color. The Background-Color will be determined by the Method public String getTrafficColor(Trgs trgs) in the TrgsLazyDataActions Bean.
But The Parameter trgs of the Method getTrgsTrafficColor(Trgs trgs) is always null and so i get a NullPointerException.
In the p:column-tag i Transfer the tempTrgs Object
#{trgsLazyDataActions.getTrafficColor(tempTrgs)}"
The tempTrgs is the var of p:datatable and it is not null.
I don't why the transferd paramter is null in the Bean.
<p:column headerText="#{texts['trgs.atp']}"
filterBy="#{tempTrgs.atp}" width="40"
style="background-color: #{trgsLazyDataActions.getTrafficColor(tempTrgs)}">
....
</p:column>
.
#javax.faces.view.ViewScoped
#Named
public class TrgsLazyDataActions extends TrgsActionsBase implements Serializable {
//The Parameter trgs is null. I don't know why ?
public String getTrafficColor(Trgs trgs) {
Factory auditedFactory = getAuditedTrgs(trgs.getTrgsID()).getFactory();
if (trgs.getAtp() < auditedFactory.getAtpMin()) {
return Consts.RED;
} else if (trgs.getAtp() > auditedFactory.getAtpMax()) {
return Consts.YELLOW;
} else {
return Consts.GREEN;
}
}
}

How to get <f:attribute> value inside <p:ajax listener> method?

I have a checkbox component with a <f:attribute> and a <p:ajax listener>.
<h:selectManyCheckbox ...>
<p:ajax listener="#{locationHandler.setChangedSOI}" />
<f:attribute name="Dummy" value="test" />
...
</h:selectManyCheckbox>
I tried to get the <f:attribute> value of test inside the listener method as below:
public void setChangedSOI() throws Exception {
FacesContext context = FacesContext.getCurrentInstance();
Map<String, String> map = context.getExternalContext().getRequestParameterMap();
String r1 = map.get("Dummy");
System.out.println(r1);
}
However, it printed null. How can I get it?
Component attributes are not passed as HTTP request parameters. Component attributes are set as .. uh, component attributes. I.e. they are stored in UIComponent#getAttributes(). You can grab them through that map.
Now the right question is obviously how to get the desired UIComponent inside the ajax listener method. There are 2 ways for this:
Specify the AjaxBehaviorEvent argument. It offers a getComponent() method for the very purpose.
public void setChangedSOI(AjaxBehaviorEvent event) {
UIComponent component = event.getComponent();
String dummy = component.getAttributes().get("Dummy");
// ...
}
Use the UIComponent#getCurrentComponent() helper method.
public void setChangedSOI() {
UIComponent component = UIComponent.getCurrentComponent(FacesContext.getCurrentInstance());
String dummy = component.getAttributes().get("Dummy");
// ...
}

How to pass a row object to the backing bean using JSF 2 and RichFaces?

I am using RichFaces's ordering list to display a table custom Command objects to the user. The user uses a form to create new commands which are then added to the list. Here is the orderingList implementation:
app.xhtml
<rich:orderingList id="oList" value="#{commandBean.newBatch}" var="com"
listHeight="300" listWidth="350" converter="commandConverter">
<f:facet name="header">
<h:outputText value="New Batch Details" />
</f:facet>
<rich:column width="180">
<f:facet name="header">
<h:outputText value="Command Type" />
</f:facet>
<h:outputText value="#{com.commandType}"></h:outputText>
</rich:column>
<rich:column>
<f:facet name="header">
<h:outputText value="Parameters" />
</f:facet>
<h:outputText value="#{com.parameters}"></h:outputText>
</rich:column>
<rich:column>
<h:commandButton value="Remove #{com.id} : #{com.seqNo}"
action="#{commandBean.remove(com.id,com.seqNo)}"
onclick="alert('id:#{com.id} seqNo:#{com.seqNo}');"/>
</rich:column>
My troubles began when I tried to implement a remove button which would send a command's ID and seqNo to the backing bean (cb) to be removed from the list. Here is the backing bean:
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
#ManagedBean
#SessionScoped
public class CommandBean implements Serializable{
private static final long serialVersionUID = 1L;
private CommandType type;
private String parameters;
private List<Command> newBatch = new ArrayList<Command>();
private Set<Command> commandSet = new HashSet<Command>();
private String msg = "not removed";
public CommandType[] getCommandTypes() {
return CommandType.values();
}
public void addCommand(CommandType type, String parameters) {
newBatch.add(new Command(type, parameters));
}
CommandType getType() {
return type;
}
void setType(CommandType type) {
this.type = type;
}
String getParameters() {
return parameters;
}
void setParameters(String parameters) {
this.parameters = parameters;
}
public List<Command> getNewBatch() {
return newBatch;
}
public void setNewBatch(List<Command> newBatch) {
this.newBatch = newBatch;
}
public Set<Command> getCommandSet() {
return commandSet;
}
public void setCommandSet(Set<Command> commandSet) {
this.commandSet = commandSet;
}
String getMsg() {
return msg;
}
public void remove(Integer id, Integer seqNo) {
for(Command c : newBatch) {
if(c.getId() == id && c.getSeqNo() == seqNo) {
newBatch.remove(c);
msg = "removed " + c;
return;
}
}
msg = String.format("%d : %d", id,seqNo);
}
}
When the Command (com)'s id and seqNo are passed via #{cb.remove(com.id,com.seqNo)} they are both 0. I also read somewhere that null values are transformed to 0's, so that would explain it. I also tried to pass the Command object directly via #{cb.remove(com)} but the Command was null when bean tried to process it.
I'm betting there is something off with the scoping, but I am too new to JSF to figure it out...
UPDATE
I have eliminated the conflicting #Named tag and have updated the html to reflect the new name of the bean, namely commandBean. Still having issues though.
you can pass the two values as request parameters:
<h:commandButton ... >
<f:param name="id" value="#{com.id}"/>
<f:param name="seqNo" value="#{com.seqNo}"/>
</h:commandButton>
and get retrieve them in managed bean like this:
HttpServletRequest request = ((HttpServletRequest)FacesContext.getCurrentInstance().getExternalContext().getRequest());
System.out.println(request.getParameter("id"));
System.out.println(request.getParameter("seqNo"));
You're trying to get a value from a variable that is used in a for-cycle after the cycle is over. The #action is being resolved on the server side, by the time the #var is null.
You can do this:
<a4j:commandButton action="#{commandBean.remove()}" … >
<a4j:param assignTo="#{commandBean.idToRemove}" value="#{com.id}"/>
</a4j:commandButton>
The a4j:param resolves the value on client side, when the button is clicked it sends it to the server.

inputHidden how to fetch value from backbean

I have an inputHidden element in a form to which i would like to fetch a property value from the backbean. Here is my JSF code:
<h:form id="imageEditor">
<p:toolbar id="theMenuBar">
<p:toolbarGroup align="left">
...
<p:commandButton value="Quit" ajax="true"
action="#{imageEditorBean.goToMainMenu()}"
icon="ui-icon-close" >
<p:ajax update="#this" immediate="true"/>
</p:commandButton>
</p:toolbarGroup>
</p:toolbar>
...
<p:fieldset id="viewer" legend="Viewer">
<h:inputHidden id="getJSONData" value="#{imageAnnotations.fetchJSONString()}">
</h:inputHidden>
...
My corresponding backbean class is:
#ManagedBean(name="imageAnnotations")
public class ImageAnnotations {
private String jsonString;
public String fetchJSONString () {
jsonString = new String();
...//populate property
return jsonString;
}
public String getJsonString() {
return jsonString;
}
public void setJsonString(String jsonString) {
this.jsonString = jsonString;
}
When the page loads value property of inputHidden field is populated BUT when i press the quit button to switch view the button is not working, and i get the following error:
Caused by: javax.el.PropertyNotWritableException: /views/image-editor.xhtml #110,82 value="#{imageAnnotations.fetchJSONString()}": Illegal Syntax for Set Operation
I have also tried to call my backbean class and populate the jsonString property like:
<h:inputHidden id="getJSONData" value="#{imageAnnotations.jsonString" action="#{imageAnnotations.fetchJSONString()}">
with no luck. Any ideas?
The inputHidden works in the same way as a inputText, except that it's not displayed in the screen. Therefore, the value property has to point to an attribute in the managed bean, with getter and setter. It can't point to a method. You will have to initialize the value of the property either in the constructor or in the #PostConstruct. If in order to populate this property you use a #ManagedProperty or a #EJB, you'll have to do it in the #PostConstruct since in the constructor they haven't been set yet.
<h:inputHidden id="getJSONData" value="#{imageAnnotations.jsonString" >
In the ManagedBean
#ManagedBean(name="imageAnnotations")
public class ImageAnnotations {
private String jsonString;
#PostConstruct
public void init() {
jsonString = ... // populate jsonString
}
// getter & setter for jsonString
}

Assign 'value expression' in place of 'method expression' in JSF

In my composite component, I iterate a list<list<javaDetailClass>>. I get all my <h:commandButon> attribute's values through value expression like #{iterator.value}. But the problem comes with attribute action, where action accepts only method expression. whereas I can assign only value expression there, resulting in MethodNotFoundException
<cc:interface>
<cc:attribute name="formElements" />
</cc:interface>
<cc:implementation>
<c:forEach items="#{cc.attrs.formElements}" var="element">
<c:forEach items="#{element}" var="iterator">
<h:commandButton id="#{iterator.id}"
value="#{iterator.value}"
action="#{iterator.action}">
</h:commandButton>
</c:forEach>
</c:forEach>
</cc:implementation>
Can anyone help me in fixing this?
Thanks in advance.
UPDATE
this will be the detail class in my situation,
package com.stackoverflow.test;
public class TestData {
/*Properties based on the implementation of your composite.
Change type where it is needed*/
private String id;
private String value;
private String attributeName;
private String action;
public TestData() {
}
/*Getters and setters omitted*/
}
Bean.java simply holds an ArrayList of ArrayList. The constructor simply created five TestData objects and assigns some default value to its attributes.
package com.stackoverflow.test;
import java.util.ArrayList;
import javax.faces.bean.*;
#ManagedBean
#RequestScoped
public class Bean {
private ArrayList<ArrayList<TestData>> list = new ArrayList<ArrayList<TestData>>();
public Bean() {
ArrayList<TestData> testDataList = new ArrayList<TestData>();
TestData data;
for(int i = 0; i < 5; i++) {
data = new TestData();
data.setId("ID" + i);
data.setValue("VALUE" + i);
data.setAttributeName("ATTRIBUTE" + i);
/**this sets the action attribute of TestData with a API from some other managed bean**/
data.setAction("someOtherManagedbean.someactionAPI");
testDataList.add(data);
}
list.add(testDataList);
}
public ArrayList<ArrayList<TestData>> getList() {
return list;
}
public void setList(ArrayList<ArrayList<TestData>> list) {
this.list = list;
}
}
index.html simply calls the composite by assinging the value of "#{bean.list} to the name attribute
I'm assuming that your TestData.java has the following method public String getAction() (since I'm seeing a setAction(String)) and not
public String action(). Therefore, the reason why you are getting a MethodNotFoundException is because you are supplying the wrong method name to the action attribute. In your case it should be iterator.getAction and not iterator.action. You only supply the abbreviated names when an attribute is expecting a value expression. The interface below has been modifed.
<cc:interface>
<cc:attribute name="formElements" />
</cc:interface>
<cc:implementation>
<c:forEach items="#{cc.attrs.formElements}" var="element">
<c:forEach items="#{element}" var="iterator">
<h:commandButton id="#{iterator.id}"
value="#{iterator.value}"
action="#{iterator.getAction}">
</h:commandButton>
</c:forEach>
</c:forEach>
</cc:implementation>

Resources