As a follow on to an answered question on Adding Components Dynamically in JSF 2.0 (see link below), I like the approach of using a dataTable, but what about Removing one of the added components?
How to dynamically add JSF components
Based on the code snippet in the other question you linked, you need to do the following changes:
Add a column with a delete button to the table.
<h:column><h:commandButton value="delete" action="#{bean.delete}" /></h:column>
Add a DataModel<Item> property to the bean and wrap the list of items in it so that you will be able to obtain the table row where the button was clicked.
private DataModel<Item> model = new ListDataModel<Item>(items);
(don't forget the getter, note that you can also instantiate this in bean constructor or postconstruct)
Use this in the datatable instead.
<h:dataTable value="#{bean.model}" var="item">
Add a delete method to the bean.
public void delete() {
items.remove(model.getRowData());
}
See also:
Benefits and pitfalls of #ViewScoped - contains JSF 2.0 CRUD table example
Related
I am using primefaces 6.2.3 sheet component. I am trying to update the backing bean when the user selects multiple rows and clicks on context menu. I am not able to retrieve the rows selected in my bean. The primefaces extension example uses JavaScript to remove the rows selected from UI without calling the backing bean.
As #Kukeltje has stated simply use a primefaces p:remoteCommand and you can use that in your Javascript code to executing backing bean methods.
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.
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().
<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
I have a form along with a add new row button. Each row consist of different fields. Now I have already defined an ArrayList of the above fields in the command bean. My problem is that how can I dynamically take in new values and bind it to my bean during the runtime. I want to add a dynamically generated list and post it back to save it in the database. How to achieve this?
For example I have form with three text areas and there is an add button. Now when I click the add button there is a dynamic generation of the three text fields on the front end. and now I have to bind it to my bean where I have declared and arraylist for this three text areas. Now how should I achieve this. My ArryList is as follows..
private ArrayList<CommText> commText;
and the class CommText has these three variables
class CommText
{
private String text1;
private String text2;
private String text3;
//Getters and Setters...
}
Try using a javascript Ajax framework such as JQuery to post this to your Controller, which can in turn update your collection.
Which version of spring-mvc / webflow are you using?
I am using JSF 2 with PrimeFaces 2.2. I tried making an ajax call through a select box onchange event in a dataTable. I was able to see the System.outs printing but, I could not see the components given in the update attribute getting updated. I have given the dataTableId in the update attribute.
I guess the problem now is the selectbox is getting populated again and an ajax call is made. Should we give only the parent tags in the update attirbute, for the ajax call to work. Please help me out in this.
When the ID in the update attribute does not start with :, it becomes relative to the ID of the current component inside the same NamingContainer component. But since the h:dataTable is an NamingContainer component, you need to reference it by an absolute ID. Rightclick the JSF page in the webbrowser and choose View Source to see the generated HTML DOM tree. Locate the HTML <table> element which is generated by the <h:dataTable>, determine the value of its id attribute and use exactly that id in the update attribute, prefixed with :.
I'm currently working on a JSF 1.2 project (IBM implementation and a "company layer").
PROBLEM
Here's the situation (numbers of items are just for the example), simple CRUD
List item
I have a list of items
I click on item 2 to see detail
I click on modify, the modification page displays values of item 2
Back to the list with a button "Back" and immediate="true" (because we don't want to submit the modifications)
Detail of item 4
Modify item 4 > Values of item 2 are displayed
BUT
if I set the "immediate" attribute of the "Back" button to false, values of item 4 are OK.
if I set the "disabled" attibute of an inputText component to true, value of item 4 is OK.
if I use <h:outputText value="#{item4.myValue}/> (UIOutput) instead of <h:inputText value="#{item4.myValue}/> (UIInput)
Also, I checked in debug mode that the bean I wanted to display was "item 4" and it was.
WHAT I FOUND
After some research on Google I found that this problem comes from the lifecycle of JSF, although the documentation and solutions found are for specific implementations of JSF.
So I guess it's because the value is populated with "localValue" instead of "submittedValue" (#see EditableValueHolder interface could help understanding), and there are some solutions from these pages
Apache wiki
IceFaces forum
RESULT
It doesn't work (I wouldn't be here, I swear ^^).
The "Refresh" solution is ineffective.
The "Erase input" is scary. I can't admit that I need to reference every input field! Plus I didn't find the setSubmittedValue() method on the UIInput in my IBM JSF.
The "Clear" method is ineffective. I tried on one element, and on the complete component tree with this code
public void cleanAllChildren(List<UIComponentBase> list){
for(UIComponentBase c : list){
this.cleanAllChildren(c.getChildren());
c.getChildren().clear();
}
}
But without success. So here I am.
Did I miss something? is there a nice tricky solution I didn't see? I'm not really familiar with the JSF lifecycle.
Put the bean with request scoped data in request scope, not in session scope.
You probably have the entire list in session to "save" DB calls and all the work to retain values in the subsequent requests inside the same session. You can use a separate session scoped bean for that, e.g. DataManager. Then you should have a request scoped bean to represent the selected item, e.g. DataItem. You can familarize the both beans with help of managed property injection.