p:datatable selectAllRows api calls don't trigger rowSelect Event - ajax

I have a p:dataTable with selectionMode=multiple which binds the rowSelect and rowUnselect event:
<p:dataTable
widgetVar="myDatatable"
selectionMode="multiple"
selection="#{myBean.selection}">
<p:ajax event="rowSelect" listener="#{myBean.onSelect}" />
<p:ajax event="rowUnselect" listener="#{myBean.onUnselect}" />
... (columns)
</p:dataTable>
Selecting rows works fine, myBean.selection is updated and myBean.onSelect() is invoked.
Now I wanted to add buttons to (un)select all items to my Toolbar. I created two <p:commandLink>s:
<p:commandLink onclick="PF('myDatatable').selectAllRows();"
update="actionbarForm">select all</p:commandLink>
<p:commandLink onclick="PF('myDatatable').unselectAllRows();"
update="actionbarForm">unselect all</p:commandLink>
The selection seems to work, I can see that either all items are (un)selected. However, neither myBean.selection nor myBean.onSelect() are updated/invoked. What do I have to do that to enable this?

These two PrimeFaces javascript api calls do in no way interact with any of the ajax events. This can be seen in the datatable.js in selectAllRows() and unselectAllRows() If you do not use ajax but a normal 'submit' via a button, you'll see that PrimeFaces expands the selection to 'all' on the server side. For this it passes the #all value of the selection to the server.
You'll also see in the source that there already is some code to send a 'toggleSelect` ajax event, so I put it in a function extending the PrimeFaces datatable:
PrimeFaces.widget.DataTable.prototype.fireToggleSelectEvent = function(checked) {
//fire toggleSelect event
if(this.cfg.behaviors) {
var toggleSelectBehavior = this.cfg.behaviors['toggleSelect'];
if(toggleSelectBehavior) {
var ext = {
params: [{name: this.id + '_checked', value: checked}
]
};
toggleSelectBehavior.call(this, ext);
}
}
}
After calling the (un)selectAllRows() via the widget, you can call this function too, with either a true (select) or false (unselect) value as the parameter.
If you then add the toggleSelect ajax to your datatable
<p:ajax event="toggleSelect" listener="#{dtSelectionView.onToggleSelect}" update=":form:msgs" />
and in your bean add a handler:
public void onToggleSelect(ToggleSelectEvent event) {
FacesMessage msg = new FacesMessage(event.isSelected() ? "All Selected" : "All Unselected");
FacesContext.getCurrentInstance().addMessage(null, msg);
}
It all works. (PrimeFaces 6.0, code tested against showcase)
You could also override both the (un)selectAllRows in the PrimeFaces datatable.js and at the end call the fireToggleSelectEvent, so all is in one functioncall (or combine both separate calls in one custom function).

Related

Kendo Cancel dropdownlist selectionChange event

I use Kendo-angular library. When user select an item in my dropdownlist, the selectionChange event is triggered and based on some conditions I want to cancel the change event and revert to previously selected value in the dropdownlist.
Can this be achieved with the kendo dropdownlist component ?
<kendo-dropdownlist
[data]="services"
[textField]="'defaultLabel'"
[valueField]="'id'"
[(ngModel)]="selectedService"
placeholder="Select a service"
(valueChange)="onServiceChanged($event)">
</kendo-dropdownlist>
onServiceChanged(event) { }
//event is the actual selected value, not the event
i found a solution:
<kendo-dropdownlist #dropdown
(valueChange)="valueChange($event, dropdown)">
</kendo-dropdownlist>
valueChange(value, dropDownControl: DropDownListComponent) {dropDownControl.writeValue("old value");}
Check the event list on the documentation
https://www.telerik.com/kendo-angular-ui/components/dropdowns/dropdownlist/#toc-events
public valueChange(value: any): void {
// Your condition here
this.log('valueChange', value);
}

Removing row not reflected in datatable after update

My delete button will delete an entry from the database but not from the actual datatable in primefaces. Until you refresh it with either a filter change or F5/new session.
I've looked at various other answers to this question and am coming up blank. I've tried messing with the update and using oncomplete="PF('datalistWidget').filter()" among other things.
Using primefaces 6.0 and glassfish 4.1. Any help appreciated.
I roughly followed the tutorial at http://www.oracle.com/technetwork/articles/java/java-primefaces-2191907.html and then added on my own customization. The managed beans and facade etc... are all similar to that tutorial with the database created classes. I have not seen any errors in the glassfish log.
DataTable
<p:dataTable id="datalist" value="#{chemicalChemicalController.items}" var="item"
selectionMode="single" selection="#{chemicalChemicalController.selected}"
paginator="true"
editable ="true"
rowKey="#{item.chemKey}"
rows="10"
widgetVar="datalistWidget"
rowsPerPageTemplate="10,20,30,40,50"
filteredValue="#{chemicalChemicalController.itemsFiltered}"
>
Delete Command Button
<p:commandButton id="deleteButton" icon="ui-icon-trash"
value="#{bundle.Delete}" actionListener="#{chemicalChemicalController.destroy}"
update=":growl, datalist" disabled="#{empty chemicalChemicalController.selected}"/>
Controller Delete Command
public void destroy() {
persist(PersistAction.DELETE, ResourceBundle.getBundle("/Bundle").getString("ChemicalChemicalDeleted"));
if (!JsfUtil.isValidationFailed()) {
selected = null; // Remove selection
items = null; // Invalidate list of items to trigger re-query.
}
}
destroy method with deleting from items object.
public void destroy(SelectEvent event) {
persist(PersistAction.DELETE, ResourceBundle.getBundle("/Bundle").getString("ChemicalChemicalDeleted"));
if (!JsfUtil.isValidationFailed()) {
selected = null; // Remove selection
items = null; // Invalidate list of items to trigger re-query.
}
RowObj rowObj = (RowObj) event.getObject();// here Row Object is your selected row item.
if(items != null)
{
//iterate items and delete matched with selected row object
}
}

Delay a JSF AJAX listener for checkbox group

I have a checkbox group (h:selectManyCheckbox) with an AJAX event to fire when boxes are checked or unchecked. This is straightforward with f:ajax, e.g., f:ajax execute="#form" event="click".
I'd like to enhance this to not re-execute after every click. Instead, I'd like an idle delay such that if the user clicks three boxes in quick succession, there's only one round trip instead of three.
Is there a way to have a JSF AJAX listener (f:ajax) fire after a delay like this?
If you're not on JSF 2.2 yet, you could use JS setTimeout()/clearTimeout() to timeout the onclick and clear any previously set ones when clicked again.
E.g.
<h:selectManyCheckbox ... styleClass="delayClick">
<f:selectItems ... />
<f:ajax ... />
</h:selectManyCheckbox>
with basically (also with a little help of jQuery)
$(".delayClick input").each(function(index, input) {
var onclick = input.onclick;
input.onclick = null;
$(input).on("click", function(event) {
delay(function() { onclick.call(input, event); }, 1000);
});
});
var delay = (function() {
var timer = 0;
return function(callback, timeout) {
clearTimeout(timer);
timer = setTimeout(callback, timeout);
};
})();
If you're already on JSF 2.2, set the delay attribute of <f:ajax>.
<h:selectManyCheckbox ...>
<f:selectItems ... />
<f:ajax ... delay="1000" />
</h:selectManyCheckbox>

Aborting JSF Ajax Request from jsf.ajax.addOnEvent()

I would like to have a central place where I monitor ajax requests and in certain situations abort them.
The only thing I don't know to do is to actually abort the ajax request from one central function.
I Imagine that the solution would look something like this:
jsf.ajax.addOnEvent(function(data) {
if (data.status === 'begin') {
// abort the ajax request
}
});
But I might be mistaken.
Thanks!
This is not possible by the standard JSF JS API. Your best bet is to add an onclick or onchange handler on the calling JSF component which returns false if the desired condition is met to abort the ajax request.
<h:commandButton onclick="return mayFireAjax(this)">
<f:ajax />
</h:commandButton>
You can if necessary abstract this away with jQuery.on() (or jQuery.delegate() or jQuery.live() depending on the jQuery version used) on a common selector so that you don't need to repeat it on every desired component.
$(someSelector).on("click", function() {
return mayFireAjax(this);
});
If you have control the source, you can always attach a onClick to the UICommand component. But in some situation, you do not have access to source. For example, the ajax is provided by some third-party component. You do not want to mess up with their components.
First, I have a small js library.
var FxJSFBegin = "JSFBegin";
if (jsf) {
var originalRequest = jsf.ajax.request;
jsf.ajax.request = function(source, oevent, options) {
var event = $.Event(FxJSFBegin);
event.options = options;
event.originalEvent = oevent;
$(source).trigger(event);
if (event.isDefaultPrevented()) {
return;
} else {
originalRequest.apply(null, arguments);
}
};
}
This piece code proxies original JSF ajax call. It uses jQuery to fire a "JSFBegin" event. Integration code can listen this event using jQuery mechanism. Listener can cancel the jsf call using event.preventDefault().
Requirement:
jQuery
This piece code should be placed after jsf.js is loaded.
Using global="false" will help you prevent calling the ajax status for an ajax call. Please refer to the following link.
Different Ajax statuses for different components in PrimeFaces

Cancel JSF ajax call

I have an f:ajax tag inside an h:inputText tag, making ajax calls on keyup events :
<h:inputText id="searchinput" value="#{tvShowForm.name}">
<f:ajax event="keyup" render="results" listener="#{tvShowForm.search}" />
</h:inputText>
Each call takes enough time that the user has typed several characters before the first call is finished.
Is there a way to cancel the current ajax call (and the queued up ones), so that the last keyup event executes an ajax call immediately?
It sounds like you want to coalesce the events, for example this will wait
half a second before firing an ajax request, and any input typed at that
point will be included. But you won't fire an ajax request for each character
typed.
<h:inputText onkeyup="keyupHandler();"/>
...
<script>
var keystrokeTimeout;
keyupHandler = function(event) {
var minChars = 4;
var len = $(this).val().length;
if((len != 0) && (len < minChars)) {
return;
}
var ajaxRequest = function() {
jsf.ajax.request('results', null, {
execute: 'results',
render: 'results'
});
}
clearTimeout(keystrokeTimeout);
keystrokeTimeout = setTimeout(ajaxRequest, 500); // millisecs
}
</script>
Is this remotely like what you want to do?
EDIT: Another suggestion is that you check out the Richfaces 4 a4j:queue functionality.
This allows for combining events, for example in the keyup scenario if you've been
leaning on your keyboard, when the current ajax request completes only one further
request will be sent. It's also possible to specify a request delay and ignore stale
responses. The big mistake Richfaces doesn't make (that primefaces does make) is that
RF uses the same underlying queue as the JSF implementation, so you don't have the risk
of out-of-order processing.
I appreciate that if you're not already using this library it's not a small step to take.

Resources