I'm learning some of JSF and I want know somethings. I already searched a lot in Google, Stack Overflow and famous websites like Mkyong and I didn't find the solution.
Actually I have one input text and a DataTable in the same page. The code appears something like this:
<h:form>
<h:inputText id="discipline"
value="#{disciplineMBean.name}"
valueChangeListener="#{disciplineMBean.updateList}">
<f:ajax event="keyup" reRender="myTable"/>
</h:inputText>
<h:commandButton value="Add" action="#{disciplineMBean.create}">
</h:commandButton>
</h:form>
<h:form>
<h:dataTable id="myTable" var="disciplina"
value="#{disciplinaMBean.disciplineList}">
<h:column>
<f:facet name="header">Name</f:facet>
<h:outputText value="#{discipline.name}" />
</h:column>
</h:dataTable>
</h:form>
What I want is: when the inputText value change, I want call the method "updateList", that will update the disciplineList with the matching disciplines (the connection with DB is ok). After that I want reRender "myTable" with the matched results - via Ajax, without page reload.
public void updateList(){
if( getName() != null && getName().length() > 0){
this.setDisciplineList( <working_connection_with_db_sending_getName()> );
}else{
this.setDisciplineList( <working_connection_with_db_all_results> );
}
}
Summarizing, I want that when user type something in input field, the disciplines list got updated with the matched disciplines - everything without page reload, when user change input field, the table is updated in real-time with the matching disciplines.
I can do something like that?
<h:inputText id="discipline" value="#{disciplineMBean.name}">
<f:ajax event="keyup" action="#{disciplineMBean.updateList}" reRender="myTable" />
</h:inputText>
Edit:
I already solved my problem, but I don't know if my way is the best way to do this things. So I will leave this question open and wait a answer explainning a better way to do this (for future users that need a similar feature). When a good answer be posted, I will give this the best answer.
Note: I translated the variable names, so sorry if I forget something.
Related
EDIT: 2017-04-28 The exact same problem (different circumstances/application) is described here: Process f:viewParam only on page load
Primefaces 6.1.RC2
JSF Mojarra 2.3.0
I already have a Java backing-bean based workaround (explained below) for the problem the following behaviour of p:dataTable causes, but I am not very happy with that workaround, and I would like to understand the behavior of p:dataTable row editing better and if possible I would like to find a purely XHTML-level solution to my problem. (BTW I am otherwise very experienced with p:dataTable, which I have used for some very complex applications for some years.)
It is not about an error or bug in p:dataTable, but the way it behaves during row editing causes me a problem in one situation.
The following code examples are completely simplified and adapted for this forum.
I have an entity Element, which has a relationship List<Link> getLinks(), where Link is also an entity.
Element has an editor edit.xhtml.
The aim is to have an composite component links_editor.xhtml that can be embedded in the edit.xhtml.
There is a CDI-compliant #ViewScoped #Named backing bean Manager.
The edit.xhtml relies on an f:viewParam to load an Element for editing:
<f:view>
<f:metadata>
<f:viewParam name="id" value="#{manager.id}"/>
</f:metadata>
</f:view>
Where in the backing bean Manager:
public void setId(Long id) {
if (id != null) {
//load an Element from database for editing by id
And in the links_editor.xhtml:
<cc:implementation>
<div id="#{cc.clientId}">
<p:growl id="testgrowl"/>
<p:dataTable
id="links_table"
editable="true"
var="link"
value="#{cc.attrs.element.links}"
>
<p:ajax
event="rowEdit"
listener="#{cc.attrs.manager.onLinkRowEdit}"
update="#{cc.clientId}:testgrowl"
/>
<p:column headerText="Link title">
<p:cellEditor>
<f:facet name="output">
<h:outputText value="#{link.name}" />
</f:facet>
<f:facet name="input">
<p:inputText id="name" value="#{link.name}"/>
</f:facet>
</p:cellEditor>
</p:column>
<p:column headerText="Link URL">
<p:cellEditor>
<f:facet name="output">
<h:outputText value="#{link.urlAsString}" />
</f:facet>
<f:facet name="input">
<p:inputText id="url" value="#{link.urlAsString}"/>
<p:message
for="url"
display="icon"
/>
</f:facet>
</p:cellEditor>
</p:column>
<p:column>
<p:rowEditor />
</p:column>
</p:dataTable>
The row edit listener:
public void onLinkRowEdit(RowEditEvent event) {
Link link = (Link) event.getObject();
try {
checkLink(link); //throws if URL string malformed
JsfUtil.addInfoMessage("DEBUG: Link: "+link);
} catch (LocalUpdateException ex) {
JsfUtil.addErrorMessage(ex.getMessage());
}
}
(where JsfUtil obviously just leverages FacesContext.getCurrentInstance().addMessage(...))
The issue/concern:
If I edit a Link row in the p:dataTable a first time and then use the "tick save" the onLinkRowEdit listener is invoked, but the diagnostics show that the value appear not to have changed. The reason is that this f:viewParam is invoked:
<f:viewParam name="id" value="#{manager.id}"/>
This (via routes not shown in detail) loads the Element entity again from database via setId(Long id), so that in the composite component edit_links.xthml this essentially resets #{cc.attrs.element.links}, so any changes are discarded.
The interesting thing is that if (without reloading the entire #ViewScoped page) one edits the same p:dataTable row a second time that f:viewParam is NOT invoked, and thereafter it works as desired.
A workaround (rather hacky) is to "block" any attempt to reload the Element by id within the view scope backing bean Manager:
public void setId(Long id) {
//HACK/WORKAROUND: prevent reload of Element by id
if (Objects.equals(id, this.id)) {
return;
}
if (id != null) {
//load an Element from database for editing by id
To be clear, I am aware of the usual strategies for using #PostConstruct and/or lazy database fetching in getters of frequently accessed info under JSF in backing beans. And I don't want to abandon here the f:viewParam approach entirely (and it works well for other situations the same Manager bean is also used for).
My interest is specifically about Primefaces p:dataTable:
Q1: Why does p:dataTable need to call the f:viewParam during the 1st row edit then "tick save", when the row information (in this cases element.links) is clearly already available ?
Q2: Why does p:dataTable NOT need to call the f:viewParam during the 2nd row edit then "tick save" ?
Q3: Is there a JSF XHTML-based way of preventing p:dataTable from calling the f:viewParam at all during a rowEdit then "tick save" (including the 1st go) ?
UPDATE: 2017-04-21: There is now a mini test web app for NetBeans 8.2 demonstrating the problem at:
https://github.com/webelcomau/Webel_PrimeFaces_test_p50445_dataTable_fviewParam
Please just download the master ZIP-archive, unzip it, and open it in NetBeans IDE 8.2. You don't need to Git-clone the project. Make sure you have Glassfish-4.1.1 set as the server for the project.
Both the README there and the web app test page itself give precise steps for reproducing the problem (or the behavior that concerns me).
I have invested some effort in analysing this because I use p:dataTable "embedded" in edit forms together with f:viewParam a lot, and I want to understand this matter better, even if it is not an actual problem with p:dataTable.
I have an h:dataTable inside of an h:form, where each row has it's own h:commandButton type="submit" action="#{bean.saveChanges(item)}".
f:inputs are declared as required and they also need to match a pattern.
If every input is in the right format, then it works fine.
Otherwise it needs only one input to be wrong and an updating function on a commandButton corresponding to a completely different item in another row seems not to be called, therefore not updated in the database.
Also only the wrong row's validation message is displayed and the changes are maintained in the view by a (backing Spring view scoped) bean, so the user might actually think, that the initial row was indeed updated in the database too.
Is there a way, how to separate individual rows of the h:dataTable, so that the validation messages of another row does not stop other items from being updated by the method of a (Spring/backing) bean?
Use ajax to process/execute only the current row. You can achieve that by explicitly specifying the client IDs of the input components in <f:ajax execute>.
<h:form>
<h:dataTable ...>
<h:column>
<h:inputText id="foo" ... />
</h:column>
<h:column>
<h:inputText id="bar" ... />
</h:column>
<h:column>
<h:inputText id="baz" ... />
</h:column>
<h:column>
<h:commandButton ...>
<f:ajax execute="foo bar baz #this" ... />
</h:commandButton>
</h:column>
</h:dataTable>
</h:form>
This won't process the inputs in other rows. Use if necessary <f:ajax render> to update the <h:message(s)> associated with the inputs.
See also:
Understanding PrimeFaces process/update and JSF f:ajax execute/render attributes
The required on the input cause the Process validation to fail and the render response to be invoked.
A simple solution could be You could remove the required from the input and handle the case in you managed bean. Since the action would move on till Phase 5: Invoke application the valid data can be saved. For all invalid rows highlight the row by having a boolean in you data model.
Primefaces 3.5 doesn't seem to filter data at all from the datatable, oddly enough it somehow reorders them as I type, so, there must be some AJAX calls firing, but obviously not the right ones.
<h:panelGroup id="table-wrapper-component">
<prime:dataTable
rendered="#{artifactSelectionBackingBean.visibleComps}"
value="#{artifactSelectionBackingBean.components}"
var="tagInfoObject" emptyMessage="No tags found with given criteria"
filteredValue="#{artifactSelectionBackingBean.filteredComponents}">
<prime:ajax event="filter" global="false" />
<prime:column sortBy="#{tagInfoObject.tagId}"
headerText="Identifier" filterMatchMode="contains" filterBy = "#{tagInfoObject.tagId}">
<h:outputText value="#{tagInfoObject.tagId}" />
</prime:column>
<prime:column sortBy="#{tagInfoObject.type.tagTypeId}"
headerText="Tag Identifier" filterMatchMode="contains" filterBy ="#{tagInfoObject.type.tagTypeId}">
<h:outputText value="#{tagInfoObject.type.tagTypeId}" />
</prime:column>
<prime:column sortBy="#{tagInfoObject.title}" headerText="Title" filterMatchMode="contains" filterBy="#{tagInfoObject.title}">
<h:outputText value="#{tagInfoObject.title}" />
</prime:column>
<prime:column filterBy="#{tagInfoObject.description}"
filterMatchMode="contains" sortBy="#{tagInfoObject.description}"
styleClass="wrap" headerText="Component Description">
<h:outputText value="#{tagInfoObject.description}" />
</prime:column>
</prime:dataTable>
</h:panelGroup>
Any help is appreciated! All the Beans and method calls exist and return the appropriate data, just that the filtering doesn't seem to work at all.
Also, note that sorting functions properly only filtering does not!
The issue was that you always need to wrap any filtering/sorting attributes in a data table with an h:form tag. This is not explicitly specified in the documentation of PrimeFaces, however, it is in the showcase here. I wrapped the whole thing in form tags.
So, don't forget to wrap your data tables in a form if you want any type of interaction provided by primefaces.
Your managed Bean Code will do a lot of good
Post your managed bean code.
May be you have not set the value for artifactSelectionBackingBean.filteredComponents in the managed bean
So, I have a session scoped bean that has a 2 lists of string values. This bean is called AgreementBean.java. I'm showing these lists in a page called agreementDetail.xhtml like this
<h:dataTable id="servers" value="#{agreement.licenseServerNames}" var="licenseServerName">
<h:column>
<h:inputText value="#{licenseServerName}"/>
</h:column>
</h:dataTable>
Computer IDs<br/>
<h:dataTable id="idNames" value="#{agreement.computerIdNames}" var="computerIdName">
<h:column>
<h:inputText value="#{computerIdName}"/>
</h:column>
</h:dataTable>
As you can see, I expect user input on these values. I need to make an Ajax call to update those values when the customer clicks on a "Save button". Here's the button's jsf code.
<script type="text/javascript">
function showAlert(data){
alert("SAVED!");
}
</script>
<h:commandButton value="Save" immediate="true" type="submit" action="#{agreement.save}">
<f:ajax onevent="showAlert"/>
</h:commandButton><br/><br/>
The "Save" bean method does nothing right now, except for logging the values stored in both lists.
When clicking on the button, 2 things are happening right now. If the customer changed the values on the inputFields, the bean's list's value is set to null. If the customer didn't change anything, then the bean's original value is kept.
How can I fix this? Thanks!
There are 2 problems with your command button:
<h:commandButton value="Save" immediate="true" type="submit" action="#{agreement.save}">
<f:ajax onevent="showAlert"/>
</h:commandButton>
immediate="true" causes that only input elements which also have immediate="true" set will be processed. However, your inputs don't have this attribute set.
<f:ajax execute> defaults to #this, causing that only the command button itself is processed during form submit. Your inputs are therefore skipped in processing.
Get rid of the misplaced attribute and tell <f:ajax> to execute the entire form.
<h:commandButton value="Save" type="submit" action="#{agreement.save}">
<f:ajax execute="#form" onevent="showAlert"/>
</h:commandButton>
See also:
Why was "immediate" attribute added to the EditableValueHolders?
Then there's a potential problem with your data model. You seem to be supplying a List<String> to the data table instead of a List<SomeBean>. The String is immutable and doesn't have a setter for the value. A <h:inputText value="#{string}"> is never going to work. For the first table, you really need to have a LicenseServer bean with a private String name property. You can then use it as follows:
<h:dataTable value="#{agreement.licenseServers}" var="licenseServer">
<h:column>
<h:inputText value="#{licenseServer.name}"/>
See also:
Why input (for example h:inputText) nested in h:dataTable do not update Bean model?
Unrelated to the concrete problem, are you aware that onevent is invoked 3 times? For the purpose you'd probably like to check if ajax event status equals to "success".
See also:
Proccess onclick function after ajax call <f:ajax>
This question is similar to the question here but that solution doesn't work here.
Take this simple-to-the-max example:
<h:form>
<h:inputText required="true" value="#{mrBean.someValue}" />
<h:inputText required="true" value="#{mrBean.someValue2}" />
<h:commandButton value="Submit">
<f:ajax execute="#form" />
</h:commandButton>
<h:commandButton immediate="true" action="#{mrBean.clearAllValues}" value="Clear">
<f:ajax render="#form" />
</h:commandButton>
</h:form>
And the bean Code:
public void clearAllValues() {
setSomeValue(null);
setSomeValue2(null);
}
Take this scenario:
Enter 'X' value in first input
Submit it using the 'Submit' Button. (failed in validation)
Enter 'Y' into the same input.
Click the 'Clear' button.
Result: Inputs don't clear and value of first input returns to 'X'.
I would expect this scenario to clear the input values but it doesn't, instead, it restores 'X' which is the previously submitted value. It actually never really runs mrBean.getSomeValue() on the bean (Which would have returned null and clear the input field)
The problem is related to JSF not working well with required fields and immediate. I wonder if anyone managed to overcome this problem.
Thanks!
Ben.
Your code example is oversimplified. The described problem symptoms will only occur when you have multiple required inputs. Add one more required input field to the example. Fill out only one of them. A validation error will occur for the empty one. Then enter something else in both and press clear. The valid input will indeed retain the previously submitted value.
This problem is described in detail in this question and this blog article. The solution boils down to collecting all to-be-cleared input components and calling EditableValueHolder#resetValue() on each of them. This can be done with a <f:actionListener> as shown in the blog article.
Another way in your particular case since you just want to clear out the entire form is to use a <h:button> which will basically just refresh the page. If your bean is request or view scoped then it will also be recreated with all properties set to default.
<h:form>
<h:inputText required="true" value="#{mrBean.someValue}" />
<h:commandButton value="Submit">
<f:ajax execute="#form" />
</h:commandButton>
<h:button value="Clear" />
</h:form>
Are you sure clearAllValues is executed? Do you get any errors in the logs or console?
Try adding execute
<f:ajax render="#form" execute="#this">