simulate onclick event picklist primefaces - events

I know that the primefaces picklist only alows transfer event like
<p:ajax event="transfer" listener="#{bean.onTransfer}" />
But I am looking for an onTargetSelected event. Is there a way to simulate it?
I thought about a JQuery function bound with a click event but I don't know on which element. I saw that when I select a line in the target list, the class of the li is transforming to ui-state-highlight. Is there a way to detect class changing with JQuery?
To call a bean method when the event will be fired, I thought about primefaces remoteCommand to send the ID of my object.
Do you have an idea about this event?
Note: I saw that there is a select with the target values in the source code but the selected value is 'selected' for each item and I don't know if there is something to do with this.
Thanks for your help

I have a trick. I am using this JQuery function :
$(document).ready(function(){
$('.ui-picklist-target .ui-picklist-item td').click(function() {
var id = $(this).closest("li").attr("data-item-value");
$('[id$=selectedItemId]').val(id); // Setting the value of my hidden input
updateSelectedTarget(); // Calling the remoteCommand function
});
});
I have added this to my xhtml page
<h:form>
...
<p:pickList ...>
</p:pickList>
<h:inputHidden id="selectedItemId" value="#{modifierUOBean.selectedTargetId}"/>
<p:remoteCommand name="updateSelectedTarget" actionListener="#{modifierUOBean.onSelectedTarget}"/>
</h:form>
And the bean:
private int selectedTargetId; // and getters and setters
public void onSelectedTarget() {
// Do what you want with selectedTargetId which contains the id of selected item
}

Related

How to only update JSF/Primefaces component value upon Ajax sucess, but do nothing on Ajax failure

I have a JSF front end using Primefaces 5.3 which updates fields dynamically using Ajax. The problem that I am having is that sometimes my Ajax calls fail (ex: server responds with a 500), but my front end is still changing. Essentially, I'm looking to prevent the change of the input field if my ajax fails. Stated differently, I only want the input field to change upon a successful Ajax response.
I'm fairly new to JSF, so I'm not sure how to handle this. In regular HTML/JS, I would have been able to store the value onclick and in my ajax error handler restored the value, but I don't know how to do this using the PF framework.
<div class="Container25">
<p:selectOneRadio id="grid" value="#{cc.attrs.answer.singleAnswer.codeValue}" layout="grid" columns="1" >
<f:selectItems value="#{cc.attrs.menuItems}"
var="item" itemLabel="#{msg[item.code]}" itemValue="#{item.code}" itemLabelEscaped="false"/>
<p:ajax event="change" listener="#{cc.attrs.onChange}" update="#{cc.attrs.update}" disabled="#{cc.attrs.onChange == null }" global="false" />
</p:selectOneRadio>
</div>
I've tried adding the resetValues attribute to the ajax component, but that hasn't helped. Additionally, I've tried adding some custom JS in my onstart handler, but it is undefined.
I figured there must be a simple JSF/PF way of doing this, but can't seem to find it.
How can I either prevent the input value to change until the Ajax call returns successfully (ie: only change the value in the onsuccess handler) or reset my original radio button selection in the event that my Ajax call fails? What do I need to put in my onerror handler to restore the pre-ajax state?
You can use Primefaces RemoteCommand component for an easy solution, just embed it in your form:
<p:remoteCommand name="revertSomeValues"
actionListener="#{relatedBean.revertValuesToDefaults}"
update="componentId" />
And at the bean side you can manipulate the model:
#Named
#ViewScoped
public class relatedBean implements Serializable {
Integer codeValue;
//other model attributes and methods...
public void revertValuesToDefaults() {
setCodeValue(0); //supposing 0 is the default value
//handle other model attributes if needed
}
}
Now you can set the onerror callback alike -> onerror="revertSomeValues()"
You can also update the components wtih Primefaces RequestContext programatically from your bean if needed:
RequestContext context = RequestContext.getCurrentInstance();
context.update("componentId");

Do something after widgetVar.filter() is really completed and has updated p:datatable

I have a datatable (primefaces 4.0), and I'm using widgetVar to apply re-filter table after update of data.
I need to call function doSomething() ONLY when employeesDataTable_WV.filter(); has really finished to filter table and update it.
in this link is show how work filter function
https://searchcode.com/codesearch/view/2686053/
it seems to do an ajax request and than update the component.
Here my example code
<h:form id="form">
<p:remoteCommand name="myRemote" actionListener="viewEmployeesManagedBean.refreshEmployees"
update=":form:employeesDataTable"
oncomplete="employeesDataTable_WV.filter();doSomething();"/>
<p:dataTable id="employeesDataTable"
value="#{viewEmployeesManagedBean.employees}" var="employee" widgetVar="employeesDataTable_WV">
[...]
</p:dataTable>
</h:form>
I need to call doSomething function ONLY after datatable is filtered and updated by employeesDataTable_WV.filter() function.
All my tests did not work and the doSomething function is always invoked before the update of the datatable.
Thanks a lot for any help.
What you should do is to add a ajax event handler to the p:dataTable and put the doSomething() in the oncomplete of the filter event and remove it from the p:remoteCommand.
<p:ajax event="filter" oncomplete="doSomething()" />
If you do not want/need to have a roundTrip to the server, you can replace the p:ajax with the PrimeFaces Extensions pe:javascript
And if you only want it to happen when the filter() is called directly on the widgetVar, just set a semaphore directly before calling the filter() and check in the doSomething() if it was set.
<p:remoteCommand ...
oncomplete="mySemaphore = true;employeesDataTable_WV.filter();"/>
function doSomething() {
if(mySemaphore == true;) {
...
mySemaphore = false;
}
// just do nothing if called from editing in one of the filter fields
}
This should work for 4.0 but also for later versions up to the current (at time of answering) 6.1-SNAPSHOT (and most likely beyond)
See also
How can I capture the event filtering a datatable in primefaces

f:ajax don't fired with event "change"

The code:
<h:inputText id="date" value="#{holidayRequestController.dates}">
<f:ajax execute="date" event="change"
listener="#{holidayRequestController.generateDates}"
render="generateDate" />
</h:inputText>
<h:panelGroup id="generateDate" class="span8"> ..</h:panelGroup>
With this code when i using date picker to select a date in from h:inputText, and f:ajax will fire event and populate this date to generateDate component.
But when i change to multiDatePicker, f:ajax don't fired with event "change"(although it work with event "blur", but i have some problem to use "blur").
What should i do to use event "change" for multiDatePicker?
One other question: is there support f:ajax for tag h:inputHidden in jsf?
Thanks for support
That can happen if the change event is actually not fired. That can in turn happen if the input element's value is only manipulated via JavaScript and not via enduser interaction.
Basically, when JavaScript manipulates the value via element.value = newValue, and you want the change event to be fired, then the JavaScript should explicitly call element.change() on the input element being manipulated.
According to $.multiDatesPicker documentation, you can use the onSelect option to hook a function on select. In that function you can then just call element.change(). So, given an input as follows:
<h:inputText ... styleClass="multi-dates" />
then you can achieve it as follows:
$(".multi-dates").multiDatesPicker({
onSelect: function() {
$(this).change();
}
});

Can't get ajax rowSelect event to fire on PrimeFaces DataTable

I am using a PrimeFace DataTable. I want to add the ajax rowSelect event to it. However, when a row is clicked, the event is not fired.
My table is decalred like so:
<h:from>
....
<h:panelGroup id="forumPanelGroup" layout="block" styleClass="messagesPanel" rendered="#{socialAdvertiserTemplateManagedBean.displayForum}" >
<p:dataTable
id="forumDataTable"
resizableColumns="true"
var="post"
value="#{forumManagedBean.posts}"
scrollable="true"
scrollHeight="300"
paginator="true"
rows="10"
rowKey="#{post.id_value}"
emptyMessage="No posts found for the given criteria"
widgetVar="forumTable"
selectionMode="single"
tableStyle="width:auto"
paginatorPosition="top">
I have the ajax event in there like so:
<p:ajax event="rowSelect" update=":mainForm:displayPost" listener="#{forumManagedBean.rowSelect}" />
And in my backing bean, I have this function:
public void rowSelect(SelectEvent selectEvent)
{
System.out.println("Hello World");
ForumPost post = (ForumPost) selectEvent.getObject();
selectedPost = post;
}
Can anyone see a problem with my declaration that would cause the event to not be triggered. I even looked at it in FireBug, and saw this being submitted after a row is clicked:
javax.faces.ViewState 1786545179464296127:-2498355873814808136
javax.faces.behavior.even... rowSelect
javax.faces.partial.ajax true
javax.faces.partial.event rowSelect
javax.faces.partial.execu... mainForm:forumDataTable
javax.faces.partial.rende... mainForm:displayPost
javax.faces.source mainForm:forumDataTable
mainForm mainForm
mainForm:forumDataTable_i... 1
mainForm:forumDataTable_s... 0,0
mainForm:forumDataTable_s... 1
mainForm:j_idt181_active 0
mainForm:j_idt70
mainForm:j_idt72
So it looks like it is sending the rowSelect. But my server side isnt picking it up.
you must add : selection="#{forumManagedBean.selectedPost}"
inside your the setter you can display the selected object:
public void setSelectedPost(ForumPost post){
if(post!=null){
System.out.println("Hello World"+post);
}
this.selectedPost=selectedPost;
}
the ajax event in there like so:
<p:ajax event="rowSelect" update=":mainForm:displayPost"/>
i think your problem is:
<p:ajax event="rowSelect" update=":mainForm:displayPost" listener="#{forumManagedBean.rowSelect}" />
event can not be triggered, because "mainForm" can not be found;
you should add an ID to your h:form:
<h:form id="mainForm">
In place of using :mainForm:displayPost use update="#[id$=displayPost]" this will pick up displayPost directly no need to map it to any thing.
I had similar problem because click event on elements inside cell didnt propagate to the cell itself.
First you check do you have any errors in console regarding update element, then add selection attribute as it is mentioned in answers above.
If all that doesnt help try to add onclick="this.parentElement.click();" to top child element inside tablecell (datatable column).
I'm assuming you just made a typo at your form while copy-pasting here:
<h:from>
Otherwise, you should get an error with that line. Add an id to your form, so you will be able to reach it when updating.
Adding a selection to your dataTable besides selectionMode will solve your problem:
selectionMode="single" selection="#{forumManagedBean.selectedPost}"

When to use valueChangeListener or f:ajax listener?

What's the difference between the following two pieces of code - with regards to listener placement?
<h:selectOneMenu ...>
<f:selectItems ... />
<f:ajax listener="#{bean.listener}" />
</h:selectOneMenu>
and
<h:selectOneMenu ... valueChangeListener="#{bean.listener}">
<f:selectItems ... />
</h:selectOneMenu>
The valueChangeListener will only be invoked when the form is submitted and the submitted value is different from the initial value. It's thus not invoked when only the HTML DOM change event is fired. If you would like to submit the form during the HTML DOM change event, then you'd need to add another <f:ajax/> without a listener(!) to the input component. It will cause a form submit which processes only the current component (as in execute="#this").
<h:selectOneMenu value="#{bean.value}" valueChangeListener="#{bean.changeListener}">
<f:selectItems ... />
<f:ajax />
</h:selectOneMenu>
When using <f:ajax listener> instead of valueChangeListener, it would by default executed during the HTML DOM change event already. Inside UICommand components and input components representing a checkbox or radiobutton, it would be by default executed during the HTML DOM click event only.
<h:selectOneMenu value="#{bean.value}">
<f:selectItems ... />
<f:ajax listener="#{bean.ajaxListener}" />
</h:selectOneMenu>
Another major difference is that the valueChangeListener method is invoked during the end of the PROCESS_VALIDATIONS phase. At that moment, the submitted value is not been updated in the model yet. So you cannot get it by just accessing the bean property which is bound to the input component's value. You need to get it by ValueChangeEvent#getNewValue(). The old value is by the way also available by ValueChangeEvent#getOldValue().
public void changeListener(ValueChangeEvent event) {
Object oldValue = event.getOldValue();
Object newValue = event.getNewValue();
// ...
}
The <f:ajax listener> method is invoked during INVOKE_APPLICATION phase. At that moment, the submitted value is already been updated in the model. You can just get it by directly accessing the bean property which is bound to the input component's value.
private Object value; // +getter+setter.
public void ajaxListener(AjaxBehaviorEvent event) {
System.out.println(value); // Look, (new) value is already set.
}
Also, if you would need to update another property based on the submitted value, then it would fail when you're using valueChangeListener as the updated property can be overridden by the submitted value during the subsequent UPDATE_MODEL_VALUES phase. That's exactly why you see in old JSF 1.x applications/tutorials/resources that a valueChangeListener is in such construct been used in combination with immediate="true" and FacesContext#renderResponse() to prevent that from happening. After all, using the valueChangeListener to execute business actions has actually always been a hack/workaround.
Summarized: Use the valueChangeListener only if you need to intercept on the actual value change itself. I.e. you're actually interested in both the old and the new value (e.g. to log them).
public void changeListener(ValueChangeEvent event) {
changeLogger.log(event.getOldValue(), event.getNewValue());
}
Use the <f:ajax listener> only if you need to execute a business action on the newly changed value. I.e. you're actually interested in only the new value (e.g. to populate a second dropdown).
public void ajaxListener(AjaxBehaviorEvent event) {
selectItemsOfSecondDropdown = populateItBasedOn(selectedValueOfFirstDropdown);
}
If you're actually also interested in the old value while executing a business action, then fall back to valueChangeListener, but queue it to the INVOKE_APPLICATION phase.
public void changeListener(ValueChangeEvent event) {
if (event.getPhaseId() != PhaseId.INVOKE_APPLICATION) {
event.setPhaseId(PhaseId.INVOKE_APPLICATION);
event.queue();
return;
}
Object oldValue = event.getOldValue();
Object newValue = event.getNewValue();
System.out.println(newValue.equals(value)); // true
// ...
}
for the first fragment (ajax listener attribute):
The "listener" attribute of an ajax tag is a method that is called on the server side every time the ajax function happens on the client side. For instance, you could use this attribute to specify a server side function to call every time the user pressed a key
but the second fragment (valueChangeListener) :
The ValueChangeListener will only be called when the form is submitted, not when the value of the input is changed
*you might like to view this handy answer

Resources