This has to be a dumb question, but I can't seem to find the right keywords to google on: I have an action listener that can receive an event from any one of multiple checkboxes that were all generated from the same line of jsp in a dataTable. How can I tell from the action listener which one issued the event?
In particular, I need the index of the component so I can map it to an ordered list in the model. I know I can get the UIComponent object, and from there I can get the client ID of the component. And knowing that the client ID has the component's index embedded in it, yes I could do the sleazy thing, and parse the index from the client ID. But I know that would be a horrible, fragile and unmaintainable hack.
What's the right way to do this?
After an initial search, I think this could help you.
http://illegalargumentexception.blogspot.com/2009/02/jsf-working-with-component-ids.html
Have you tried to use f:param in addition to the checkbox values to pass custom parameters, so that would be more cleaner than working with ID's to manipulate business logic. ID.
Using the DataTables var attribute, you should be able to do this
<h:dataTable ... var="currentRow">
....
<h:selectBooleanCheckbox ... actionListener="#{blah.doThis}">
<f:attribute name="curRec" value="#{currentRow}" />
</h:selectBooleanCheckbox>
bean:
public void doThis(ActionEvent ae)
{
TreeMap myMap = (TreeMap)ae.getComponent().getAttributes().get("curRec");
...
}
Edit: The binding variable of your datatable should have the method getRowIndex();. That should give you the index of the record that caused the event in the table. I'm referencing an ICEfaces project, so I apologize if that isn't correct. Let me know, thx.
Related
let's say we have two types of events that will be directed to the same method as mentioned in the below example
<p:ajax event="cellEdit" listener="#{bean.eventype}"/>
<p:ajax event="change" listener="#{bean.eventype}"/>
and here is the bean method for example
public void eventype(){
println("");
}
The question is, is it possible if I want to identify which value came from which events in eventype method?
Is it possible to differentiate both mentioned events in eventype method?
Edited:
I did try to add eventype(AjaxBehaviorEvent event) and use event.getSource() but it seems like am just getting the source details like org.inputtext.component#something.
The type of event is posted in the request in order for the component being able to decode it to trigger the correct event. The parameter name is javax.faces.behavior.event, which you can get like:
String eventType = FacesContext.getCurrentInstance()
.getExternalContext()
.getRequestParameterMap()
.get("javax.faces.behavior.event");
This is implemented in PrimeFaces like:
https://github.com/primefaces/primefaces/blob/042b5a14116cd4a279a114883a8575e0788494b8/primefaces/src/main/java/org/primefaces/util/ComponentUtils.java#L197-L224
Note that you can also use the PrimeFaces constant Constants.RequestParams.PARTIAL_BEHAVIOR_EVENT_PARAM in your code instead of hardcoding "javax.faces.behavior.event".
When a JSF form field is wired into an entity bean field (which is mapped to a DB field), each setter in the entity bean is called regardless of whether the user changed the form field value in the front end, i.e. the setters on unchanged fields are invoked the same as those that have changed but their new value is the same as the old value.
My question is simple: Is there a way to configure JSF to only call the setters mapped to the fields that have changed in the front end? The reason for this is that I have a requirement by which I have to detect deltas on every persist and log them, more about which can be read in this question.
Maybe I didn't understand you clearly, but why are you mapping directly your entity beans to a JSF view ?! IMHO it would be better if you add managed beans between your JSF pages and the entities in order to better separate your business logic from data access.
Any way, I think the easiest solution to impelement for that case is by making use of Value Change Events which are invoked "normally" after the Process Validations phase (unless you make use of the immediate attribute).
The good news about Value Change Events (regarding your example) is they are invoked ONLY after you force form submit using JavaScript or Command components AND the new value is different from the old value.
So, as an example on how to use value change listeners, you can add valueChangeListner attribute to each of your JSF tags like following:
<h:inputText id="input" value="#{someBean.someValue}"
valueChangeListener="#{someBean.valueChanged} />
Then, implement your valueChanged() method to look something like:
public void valueChanged(ValueChangeEvent event) {
// You can use event.getOldValue() and event.getNewValue() to get the old or the new value
}
Using the above implementation, may help you to separate your logging code (it will be included in the listeners) from your managed properties setters.
NB: Value Change Listeners may also be implemetend otherwise using the f:valueChangeListener Tag, but this is not the best choice for your example (you can find some examples in the section below, just in case)
See also:
Valuechangelistener Doubt in JSF
JSF 2 valueChangeListener example
When to use valueChangeListener or f:ajax listener?
I often face the following problem. I have a JSF application and a facelet where I write EL expressions, like this:
<h:outputText value="#{myBean.foo}">
As long as myBean, as a variable, has a life long enough, there's no problem to evaluate myBean.foo at any given time, but if myBean is a variable that references some bean within a short period of time, when myBean.foo is evaluated it might be too late, so that JSF complains that myBean resolves to null. This is something well-known, but the problem is that it is not clear to me what to expect in different situations.
Concrete example n. 1: if you try the following with PrimeFaces OrderList:
<p:orderList value="#{bean.myValue}" var="item">
<p:column>
<p:commandLink action="#{bean.doSomething(item)}" />
</p:column>
</p:orderList>`
This is not going to work, because when doSomething is called, the item variable is no longer defined (although the object it references is still alive) and hence it's resolved to null. It's a known issue. However the same pattern works fine with <p:dataTable>, for instance. Anyway, I'm not interested right now in this specific problem, I just want to explain my doubt.
Concrete example n. 2: I have written a composite component with a backing bean. The backing bean extends UINamingContainer and uses its StateHelper to retain a model object. This composite allows to write child tags and I would like to write something like this:
<myns:myCc var="myVar">
<h:inputText value="#{myVar.foo}" />
</myns>
With "myVar" I want to give a name to the model object. To make this work, I tried to store the model object in the request map at the beginning of encodeChildren method and remove it afterwards: this works for rendering, but if I then process the input with a commandButton action, it does not work because when the action gets executed it says that myVar can't be resolved: in other words, it tries to resolve the entire expression too late. I then tried to "permanently" save the model object in the view scope map, but it doens't work either. However, if I change this to:
(assuming modelObject is the property field in the backing bean that stores my model object)
it works. So, it is not a problem in my model, but in the way I try to make the model object available to EL expressions for child tags.
Concrete example n. 3: I often use the <ui:param> tag to give beans a shorter name and to ease templating. For instance:
<ui:param name="bean" value="#{longNamedAndPageSpecificBean}" />
So that, in the remainder of the page I can just use #{bean.foo} instead of #{longNamedAndPageSpecificBean.foo}. This works fine even for actions passed to command buttons. However, if I pass a method expression like #{bean.myActionMethod} to a composite component attribute declared with method-signature, when this method expression is actually invoked I receive an error that bean resolves to null... The reason why it works in one case (with commandButton actions) and not in the other (with actions used by the composite component) is a big source of confusion for me.
I would appreciate if someone can help me to understand better this JSF aspect and suggest better approaches/workarounds with the aforementioned concrete examples.
Your question looks too large, but i could say that, during the build time only Session and request scoped values are avaiaible.
The same thing is true for the Execution phase.
Only the render phase should ensure the avaibility of temporal vars "myVar".
The best way to understand what its realy hapening is to debug because its depends on the component implementation
I have a table in my jsf application with some data from the database. I have made the id values a link, and my goal is to pass the data from the selected row to another facelet. How can I do this? The href I have is:
<td>#{product.id}</td>
So the goal is that when the user clicks the link, the editOrDeletePage is displayed, and I want the editOrDeletePage to "ingest" the product id, so that it knows what data to display? How can I do this?
If you definetely want to use static links, you may, of course, just read a request parameter from a target page using some kind of event listener
<f:event listener="#{bean.preRender}" type="preRenderView" />
And read the parameter from request:
FacesContext facesContext = FacesContext.getCurrentInstance();
String productId = (String) facesContext.getExternalContext().
getRequestParameterMap().get("productid");
But it's not really a JSF way to handle navigation, I belive. You may want to use commandLink or some other way of handling user actions. Or maybe, even better, think of using data table, where a user can choose a row, and you can process selection.
I have a search screen where I search for a customer id and it consumes a webservice a returns list of objects. I display the results in a datatable.For a specific field , I have a method which provides the value based on a key value in each row of the list being iterated. The key value is productID. I set that in a bean named output. In the getCustomerValue method I call the method which provides the relevant value by passing the value of "productID". I use the below listed code to do the same.
<h:outputText id="customerID" binding="#{myBean.output}" value="#{customerBean.customervalue}">
<f:attribute name="myID" value="#{item2.customerService.productID}"/>
</h:outputText>
The value gets displayed properly when the page is loaded. I have hyperlink in the same page which basically calls the same webservice and renders the same page.But this time around all the values except the value listed above is being displayed. When I print the value of attribute "item2.customerService.productID" in the method "customervalue" , it is displayed as null.I am not sure why this value isn't being passed.
You're displaying this in a <h:dataTable>. The <f:attribute> is specific to the component itself, not to its generated HTML output. The <f:attribute> is evaluated during view build time, not during the view render time. At the moment JSF builds the view, the #{item2} is not present in the scope. It's only present in the scope when JSF renders the view.
You need to look for the solution by alternate means. It's unclear what JSF version you're using, but based on your question you're using JSF 1.2 (in the future questions, please explicitly mention the JSF impl/version you're using; in JSF 2.0 a lot of things can be done differently and much more elegantly).
My answer on your previous question of Passing parameters to a method in h:outputtext tag should be the best answer to your current problem. This is apparently not an option somehow. In that case, there are at least 3 alternative ways:
Move the property to the class behind #{item2}:
<h:outputText value="#{item2.customervalue}">
You've in there instant access to the customerservice property.
Get the current item inside the getter by evaluating EL programmatically:
public String getCustomervalue() {
FacesContext context = FacesContext.getCurrentInstance();
Long productID = context.getApplication().evaluateExpressionGet(context, "#{item2.customerService.productID}", Long.class);
// ...
}
(I assume that productID is a Long)
Bind the datatable's value to a DataModel:
private DataModel<Item2> items;
with
<h:dataTable value="#{customerBean.items}" var="item2">
and
public String getCustomervalue() {
Item2 item2 = items.getRowData();
// ...
}