Reputation: 3610
I think I am wasting my time yet again figuring out how to do such a simple thing in JSF, but assuming the following set-up:
<h:form id="form">
<h:dataTable id="table">
<! -- not shown: other columns with other input fields -->
<h:column>
<h:inputText id="myinput">
<f:ajax execute="@this" render="????" listener="#{bean.action}" />
</h:inputText>
</h:column>
</h:dataTable>
</h:form>
What do I specify in the render tag to ONLY re-render all "myinput" components across all rows in the datatable, ie without specifying "@form" that will re-render the other components as well? I have tried @this and ":form:table:myinput", but it always just re-renders the very first row of the dataTable. It seems like this should be such a simple use-case, so I have to obviously be misunderstanding something.
Note: I don't know if internally JSF creates N HtmlInputTextComponents for each row or just 1, but obviously when I say "all myinput components", I mean all rendered input fields back to the browser that were generated from the h:inputText tag and that have the same browser DOM id of form:table:myinput:n.
As a corollary and additional question, I don't want to process or re-render the whole form components because of possible validation/conversion errors. I simply want the following to happen: only the initiating "myinput" component that triggered the ajax call is validated, and if success, all of the other "myinput" components are populated and subsequently re-rendered with new model values that were changed from the action listener "#{bean.action}".
Additional information: I am currently using the mojarra implementation version of JSF 2.1 (I think). I would like to avoid any third party JSF libraries.
Bonus questions (which perhaps the answer to my original question would also answer):
- How to re-render and/or execute all input components but only for a single row
- How to re-render and/or execute set of input components but only for a single row
- How to re-render and/or execute all input components for a set of rows (not all)
- How to re-render and/or execute set of input components for a set of rows (not all)
To everyone replying that I can set the id of the inputText based upon the current rowIndex or current iteration variable - NO, that does not work. See: Set id of a component within JSF dataTable to value from current item in the array
I really think the only way to accomplish what I want is to abandon using a datatable and render the table columns/rpws with JSTL myself such that I can assign unique ids and have full control. However, I still think this is a huge design flaw in JSF to not support such a seemingly simple use-case.
Upvotes: 2
Views: 1768
Reputation: 1108632
What do I specify in the render tag to ONLY re-render all "myinput" components across all rows in the datatable, ie without specifying "@form" that will re-render the other components as well?
TL;DR: How do I re-render the entire column?
This is not possible using standard JSF facilities. You basically need to (auto)generate the collection of client IDs form:table:0:myinput
, form:table:1:myinput
, form:table:2:myinput
, etc yourself based on row count/index, and manually add them all to the PartialViewContext#getRenderIds()
collection during #{bean.action}
. It's not possible to specify them in render
attribute as those client IDs don't exist in JSF component tree, but JSF strictly wants to validate them (and you thus end up with confusing "cannot find client ID" exceptions).
I'm aware that you want to avoid 3rd party libraries, but OmniFaces Ajax#updateColumn()
provides exactly this functionality which only takes the table component and the (zero-based) column index as arguments. E.g.
public void action() {
// ...
UIData table = Components.findComponent("form:table");
Ajax.updateColumn(table, 2); // Updates third column.
}
Feel free to borrow/steal/improve the source under Apache 2.0 license if the remainder of OmniFaces isn't sufficiently convenient to not anymore consider it as an "average" 3rd party library.
We have by the way a possible enhancement in the queue for a future OmniFaces release, which must make this kind of requirements more hair-friendly: event driven updates.
- How to re-render and/or execute all input components but only for a single row?
- How to re-render and/or execute set of input components but only for a single row?
You can specify them in render
attribute using relative client IDs like so:
<h:column><h:inputText id="input1" ... /></h:column>
<h:column><h:inputText id="input2" ... /></h:column>
<h:column><h:inputText id="input3" ... /></h:column>
<h:column><h:inputText id="input4" ...><f:ajax render="input1 input2 input3" ... /></h:inputText></h:column>
Note: there's no way to explicitly say "all input components". You'd have to specify them individually. If you happen to use PrimeFaces, or are open to using it, then PrimeFaces Selectors would make this much easier. See also among others How do PrimeFaces Selectors as in update="@(.myClass)" work?
- How to re-render and/or execute all input components for a set of rows (not all)
- How to re-render and/or execute set of input components for a set of rows (not all)
Also here, no standard facility. You could extend on the aforementioned Ajax#updateColumn()
source code. The key problem is that you wanted to update other rows as well than only the current row. For that you'd really need to (auto)generate full client IDs and add them to PartialViewContext#getRenderIds()
.
Upvotes: 4
Reputation: 461
<h:form id="form">
<h:dataTable id="table" rowIndexVar="idx">
<! -- not shown: other columns with other input fields -->
<h:column>
<h:inputText id="myinput#{idx.index}">
<f:ajax execute="@this" render="????" listener="#{bean.action}" />
</h:inputText>
</h:column>
</h:dataTable>
</h:form>
using firebug, you can see that all your inputs have an id now. Now, you can put in your render what you want according to this id.
you must use
RequestContext.getCurrentInstance().update(lstIndex);
in your java code where lstIndex is the list of ids that you want to update
Upvotes: -2