Problem with Primefaces Autocomplete Component - jsf

I have a local Web Application developed with JDK 8, JSF 2.2 (implementation provided by JBoss), Spring 4.2 and Primefaces 6.2
In the application, I have one XHTML page for edit some fields of an object that is instance of a class named SiepRoEncabezado. One of those fields is an instance of SiepRpaPescador.
Until yesterday, I had one <p:selectOneMenu> contained in a form that is contained in a modal dialog in order to select one SiepRpaPescador object. The modal itself has 2 submit <p:commandButton> (one for save the changes and one for clean the form) and some aditional input fields.
The modal is developed in such manner that it closes automatiquely when the data is successfully edited after I push the save button.
The modal with the <p:selectOneMenu> worked fine, but due to the fact that there are too many select items to be handled in terms of memory usage, I was forced to replace the <p:selectOneMenu> by the following component:
<p:autoComplete dropdown="true"
id="rpaAutoComplete"
value="#{correccionROBean.tmpPescador}"
var="itemRpa"
itemLabel="#{itemRpa.nmPescador.concat(' ').concat(itemRpa.nmPaterno).concat(' ').concat(itemRpa.nmMaterno)}"
itemValue="#{itemRpa}"
completeMethod="#{correccionROBean.filtrarRpa}"
minQueryLength="4"
maxResults="10"
forceSelection="true" />
There, tmpPescador is a bean in the Managed Bean CorreccionROBean.
The complete method there works fine and the selection items are displayed as desired.
However, after I select one item in the <p:autoComplete> component and push the button to save the changes, it does nothing at all. Also, it does not display an error message and it does not throw any exception. What is worst, if I try to debug the action listener method in the button to save changes, it does nothing, it's like the action listener method is not called at all.
I put an <p:ajax> tag hoping to solve the problem with no avail:
<p:autoComplete dropdown="true"
id="rpaAutoComplete"
value="#{correccionROBean.tmpPescador}"
var="itemRpa"
itemLabel="#{itemRpa.nmPescador.concat(' ').concat(itemRpa.nmPaterno).concat(' ').concat(itemRpa.nmMaterno)}"
itemValue="#{itemRpa}"
completeMethod="#{correccionROBean.filtrarRpa}"
minQueryLength="4"
maxResults="10"
forceSelection="true">
<p:ajax event="itemSelect" listener="#{correccionROBean.onRpaSelect}" update="rpaAutoComplete"/>
</p:autoComplete>
Here, when I select one item, the listener method is not triggered. When I try to debug the method, it's like the method is not called at all.
Finally, when I push the save button without selecting an item in the <p:autoComplete>, then and only then, the action listener method in the save <p:commandButton> is triggered.
What may cause this behaviour?
Thanks in advance.
EDIT
I added the field immediate="true" to the autocomplete component and that triggered the ajax submit method, but still cannot execute the save button action listener method

SOLVED.
Refeer to Melloware's answer and my reply to that answer for more details.
For those that are unfamiliar with Converters:
The interface Converter, defined in JSF's API, allows to convert the data inputted and outputted to a Auto Complete component (and some other JSF UI components as well and their sub-classes). This interface has two methods:
public Object getAsObject(FacesContext context, UIComponent component, String value): This method must return an Object that is instance of the same class as the value defined in the value field of the Auto Complete component (in my case, it returns a SiepRpaPescador object). You must handle exceptions in this method as it is called automatiquely in two situations:
When you input characters in the Auto Complete text field and the number of inputted characters are equal or greater than the value defined in the minQueryLength field of the Auto Complete component or it's default value if not specified (in my case, when I input 4 characters or more). In this case, the value parameter in this method will be the String you inputted. Notice that if you enabled dropdown (dropdown="true")as in my case and you push the dropdown button, this method is NOT called.
When you submit the form. In this case, the value will be the value of the labelValue field in the Auto Complete component (in my case, #{itemRpa.nrFolio}) converted to String using the toString method defined in the class that value is instance of (#{itemRpa.nrFolio} is an Integer, so the value will be converted using the Integer class' own implementation of toString()) or in the Object class if no implementation of toString() is defined.
public String getAsString(FacesContext context, UIComponent component, Object value): This method must return a String representation of the label value of each item to be displayed in the Auto Complete component. The parameter value is an instance of the same class as the value defined in the labelValue field of the Auto Complete component. This method is called automatiquely when the items are displayed (it doesn't matter if you inputted characters in the Auto Complete's text field or pressed the dropdown button if present) and it's called as many times as defined in the field maxResults (in my case, 10) in the Auto Complete, using the objects obtained from the returned list of the completeMethod (in my case, from each object in the list obtained from #{correccionROBean.filtrarRpa}, this method obtains it's nrFolio, as I stablished in the labelValue field of the AutoComplete).
I hope this helps to you all

Related

Getting a null value passed to a Java function via BootsFaces datatable

I am trying to create a modal to send user-selected requests to an email address; however, I am having trouble getting the user-selected requests. I keep getting the null value passed through fooBean.setSelected(id).
Versions:
BootsFaces: 1.3.0
Java: 1.8.0
JSF: 2.0
Browser: Internet Explorer 11.2x
MCVE of thisThing.xhtml:
<b:dataTable value="#{fooBean.newRequests}"
var="foo"
onselect="ajax:fooBean.setSelected(id)"
ondeselect="ajax:fooBean.setSelected(id)"
selectedItems="row"
selection-mode="multiple"
selectedRows="#{foo.selected}"
saveState="false">
<b:dataTableColumn label="Select">
<b:selectBooleanCheckbox value="#{foo.selected}" />
</b:dataTableColumn>
<b:dataTableColumn label="Status" value="#{foo.status}" />
<b:dataTableColumn label="Request Number"
value="#{foo.requestNumber}"
data-type="string" />
<b:dataTableColumn label="ID" value="#{foo.id}" />
<b:dataTableColumn value="#{foo.storeName}"
label="Store Name" />
</b:dataTable>
MCVE of fooBean.java:
#ManagedBean(name="fooBean")
#ViewScoped
public class fooBean extends BeanBase implements Serializable {
private List<FooRecord> fooRecords = new ArrayList<FooRecord>();
private List<FooRecord> selectedFooRecords = new ArrayList<FooRecord>();
// ...
public void setSelected(String requestId) {
// This is not how I really do it, but it gives an idea
// with what I intend to do.
this.fooRecords.stream().filter(...).toggleSelection();
this.selectedFooRecords.stream().filter(...).toggleSelection();
}
}
Update:
I found out that I had the method called as getSelect instead of getSelected, so I fixed it and that part is done. I just remembered the real issue which is why a null parameter is being passed instead of the requestId. When I debug through the fooBean.getSelected(String requestId), it shows null being passed through as parameter. I have even tried:
<!-- Using varName.property -->
onselect="ajax:fooBean.setSelected(foo.id)"
<!-- Using just the property name -->
onselect="ajax:fooBean.setSelected(id)"
<!-- Using the loop variable -->
onselect="ajax:fooBean.setSelected(foo)"
Update 2:
How do I pass foo.id to the function?
There are only three parameters you can pass to the bean method:
The loop variable. In your example, that's foo. This parameter only works if the attribute selected-items is set to rows. Caveat: if you activate column or cell select mode, this parameter is still passed to the server, and it seems to be valid. Only that every attribute of this object is null.
typeOfSelection. This is either "row", "column" or "item". It determines what the user has selected. That, in turn, is determined by the attribute selected-items, so you hardly ever have to use this parameter. Just omit it from the parameter list.
indexes tells the JSF bean which rows, columns or cells have been selected. Note that in the first two cases this is either an individual number or - if multiple items have been selected - a comma separated list. If you've set selected-items="cell", indexes is a comma-separated list of objects containing the row and column index.
I suppose indexes or foo is the most useful parameter in your case.
Final remark: we'd like to add more flexibility, but this requires much more understanding of the internal API of JSF than even we have. Truth to tell, I'm not even sure we can pass arbitrary bean values without modifying the JSF engine itself. If anybody knows how to do that, please leave a message at our bug tracker.
Update:
Maybe the problem is caused by the modal. The modal is rendered at load time, but shown later, when the user has selected a row. Thing is, the modal isn't re-rendered automatically unless you add the content of the modal to the update attribute.

How to avoid APPLY_REQUEST_VALUES phase for particular event

I have a requirement wherein the form displays many input fields from model object.
And on one of the fields an external plugin is invoked and the value of that field is directly changed in the model by that plugin (not changed in UI form field), now I would like to reRender that panel so that changed value (from model object) is displayed onto UI form field.
Verified everything and plugin is also able to change value in the model and its also triggering reRender of the panel. When reRender, what happens is the values in UI form are applied to model and model object loses the value (set by plugin) and when panel is refreshed I would still see blank Field.
Is there a way that only for this event I bypass APPLY_REQUEST_VALUES so that values in model are displayed? Or is there a better solution for this?
Regards,
Satya
You can use immediate="true" for this.
<a4j:support ... immediate="true" />
This way only the current component will be processed.
Another way is to just proceed to render response immediately in the value change listener so that the Update Model Values (and Invoke Action) phase is skipped.
FacesContext.getCurrentInstance().renderResponse();

h:outputtext issue in passing attributes

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();
// ...
}

Save all rows in an h:dataTable

I have a Facelets page with a h:dataTable. In each row of the h:dataTable, i am displaying some enabled and disabled services of a user.Here is the model object
public class ServiceList {
private long userId;
private long serviceGroupId;
private String serviceGroupName;
private long serviceId;
private String serviceName;
private String serviceUrl;
private String serviceState;
public UserServiceList() {
}
//getters and setters....
}
These are the details i am displaying in a single row of a dataTable.
serviceState in the above model object is either 'Y' or 'N'.
my problem is the application user should be able to update the servicestate of all rows of a dataTable at once and update them in the backend database.
1)what additional JSF component do i need to use inside dataTable to achive this? I am thinking of adding one more column with h:selectOneradio
2)How do i get which rows are selected and what status they have set?
I am kind of newbee to JSF.Please help.
Update:At present what i am having is two buttons namely 'Disable Service' and 'Enable Service' in the footer section of the table.
Onclick of Disable Service i am navigating to another page where i show the application user the list of enabled services to disable
And vice-versa for Enabled service button click.
So, let's say you in your Managed Bean you have a list of services you would like the user to edit:
List<Service> serviceList;
You take this List to be displayed in the data table.
<h:dataTable value="#{yourManagedBean.serviceList}" ... >
Then you can implement a commandButton that has either an action or an actionListener which points to a certain method of your managed bean, like this:
<h:commandButton action="#{yourManagedBean.saveAllAction}" ... >
And the corresponding method to save 'em all is quite straight-forward. You iterate over the managed bean field serviceList and persist every single entry (however you persist them, like calling the EntityManager when using Hibernate or any DAO class in between, you name it.)
Concerning the service status: I'd preferably use a selectBooleanCheckbox for toggling the status, since it's probably a boolean value.
Edit after comment 1:
You have the serviceStatus in your Service class. Currently it's a string, but I suppose it should be boolean to toggle active/inactive. If this property is displayed by the selectBooleanCheckbox it is automatically changed in your corresponding Java class. So calling getServiceStatus() returns true or false, depending on what is selected in the frontend. If you persist the whole Service object then, you don't have to do anything because any modifications made in the frontend HTML elements are automatically projected to the Java object behind it.

Commandlink action and #viewscoped weird behaviour

I have some code generated by netbeans wizard 'JSF pages from entity classes'.
For those who don't use netbeans I will briefly describe what the wizard does.
It creates a JSF page List.xhtml which contains a datatable with a fixed size of ten rows and two commandlinks for scrolling its content (prev 10 and next 10).
The JSF page uses a managedbean with session scope and the above mentioned commandlinks return the String 'List'.
If I change the managed bean scope to #viewscoped it is re-created every time I push a commandlink. According to me it is a weird behavior because the view actually doesn't change (it always List.xhtml ) and I would have expected a smarted view scope mechanism.
I then changed the action associated to the commandlinks with a new one which does the same things but returns void. Now the #viewscope mechanism works well but I'm not sure it is correct to use an action method with a signature like this
public void doSomething()
// instead of
public String doSomething()
My concern is that a different JSF implementation can act in an impredictable way with that kind of actions.
Thanks
Filippo
What do you return in public String doSomething()?
If you return null (or an empty String) it should not re-create the view.
If you return a navigation case then the view is re-created, regardless whether it is the same that you are currently in.

Resources