I have a datatable with 10 rows. The first column in each row has a valuechange event. For e.g it's like, we enter the accountnumber and the valuechangeevent retrieves the account information.
Now, i also have another column to display the cost. If user enters some amount, it should add up all the amounts in all the rows and display it on a different column.
But the problem is, the user can enter a second account number at any point of time. then it will again be a valuechange event. now, since it is a value change event, the information in the first row is not updated in the DataModel. As such, i am losing the previously entered amount for the first row.
Is there a way to implement this functionality without losing the previous information?
Until just recently, I would have said that there is no way to do what you want. After a lot of research on the JSF lifecycle phases, I believe there is a way to get this to work within JSF, without having to go to an Ajax-like approach.
The essence of the problem is the rigid order of lifecycle phases in JSF. Updates to the data model (the backing bean) don't occur until after the request parameters have been parsed and standard validation rules applied. Value Change Events, which can only be fired from certain input components such as HtmlInputText, HtmlSelectOneRadio etc, occur from a component with the immediate="true" attribute set. When this happens, a specified ValueChangeListener will be called at the "Apply Request Values" phase, which will happen before the model data is updated. If you want to skip validation and updating of model data, you have to call renderResponse( ) on the FacesContext, and that will skip those phases...if you don't, it will proceed through validation and model data update normally.
Here is an example of a properly formatted JSF component that will do as I described:
What does the onchange="submit( )" do? It causes the form to be submitted to the URL specified in the form tag...in the case of JSF, all pages submit back to themselves, and are trapped by the FacesServlet. At this point the JSF lifecycle takes over, which includes the following phases: 1. Restore View 2. Apply Request Values 3. Process Validations 4. Update Model Values 5. Invoke Application 6. Render Response
So far, so good...the problem occurs when a component (specified with an immediate="true" attribute) needs to update another component, such as a text box. For this to work, both components have to have the immediate="true" attribute set. If you do this, you will be able to set the value in the second component directly in the ValueChangeListener method, in a manner something like this:
I think this will get you through the problem you are describing. If it doesn't, there is another approach that requires you to manipulate the event queue directly, and you really shouldn't go there unless absolutely necessary.
Good luck, and let me know if this works.
Joined: Oct 14, 2003
Thanks Tom for such a clean and detailed explanation.
Actually i dint get what you were trying to do in that code. Let me give my problem:
I have 3 valueChangeListeners in a datatable on the JSP.
the first textbox will populate the entire row based on the textfield value. The second and third valuechangelisteners update the costs of all the rows.
here is the jsp:
After i populate the first row, i select pInd and fAmount...fields and now, if i enter the empNo in the second row and populate it, the values i entered in pInd and fAmount for the first row are lost.
Are these not supposed to be in the modelTable that is bound to the Backing beant? Am i missing something here?
and here is the code in the valueChangeListener and the binded HtmlDataTable:
When i see the console for the changed values, the Modeltable doesn't show the values selected for the first row.
i know that value change listener doesn't update all the request values. But i want the values selected in the first row too.
Just registered and logged in to thanks for the useful advice by Tom Fulton. I was facing this problem:
I need to capture a string in an InputText component, and everytime I press Enter, the value should be processed, a search done in a database and some data updated in a datatable component. But, the text field should get ready for a new input, since the data already in the datatable may be related to the new input. This readiness should be done by clearing the InputText. Using the ViewRoot and immediate components as you say, have solved my problem...