Identify when the selected row in the table is already selected - jsf-2

I have a p:datatable in primefaces and i have different listeners for differents ways to select row event in datatable.
I need identify when the selected row in the table is already selected, how can i do that?
I need this because i dont wonna that p:blockUI runs when i select row in the table that is already selected.
There is my page code:
...
<pe:blockUI autoShow="true"
source="itemsDT"
event="rowSelect"
target=":processTab">
<au:loading />
</pe:blockUI>
<p:dataTable widgetVar="processesTable"
id="itemsDT"
var="item"
value="
{tasksbacking2.availableProcesses}"
selection="#{tasksbacking2.selectedProcess}"
rowKey="#{item.id}"
tableStyleClass="table
table-condensed table-bordered"
resizableColumns="true">
<p:ajax event="rowSelect"
listener="#{tasksbacking2.onClickFillDetails}"
update="#this,:processTab,:menuForm:menuBar" />
...
</p:dataTable>
...
On managed bean i have this listener:
...
public void onClickFillDetails(SelectEvent event) {
AnoProcess clickedProcess = (AnoProcess) event.getObject();
setSelectedProcess(clickedProcess);
Movement currentMovement = this.getProcessesLastMovement().get(clickedProcess);
if (currentMovement != null && !currentMovement.isViewed()) {
markAsRead(processes);
}
...
}

Here is the script to check for duplicate click on same row.
Put this script below your p:dataTable code.
<script type="text/javascript">
var prevRow ;
function checkDupRowClick(){
var currRow = $('tr.ui-widget-content.ui-datatable-selectable[aria-selected="true"]');
if($(currRow).is($(prevRow))){
//selected or clicked same row so return FALSE to prevent p:ajax from executing
return false;
}else{
//selected or clicked different row so return TRUE to allow p:ajax to execute
prevRow = currRow;
return true;
}
}
</script>
AND use function as a return parameter for p:ajax
<p:ajax event="rowSelect" onstart="return checkDupRowClick();" />
Post comment if you require more explanation.

I think that you need is some function in js and apply this in onstart.
like that
<p:ajax event="rowSelect" onstart="???" />

Related

How to pass a value on selected row change?

I have this permanent problem, I have a Datatable with value="#{myBean.Items}" var="itms", and I want to pass the selected item to my bean class.
In columns, we use <f:setPropertyActionListener value="#{itms}" target="#{myBean.selectedrow}" /> to pass the value, but I want it for Rows.
How to do that?, and where to put this listener?.
Thank you very much.
What richface version are you using?
For richfaces 4.3.x, the following example might do the trick:
XHTML:
<rich:extendedDataTable
id="myTable"
value="#{crudBean.rows}"
var="rowItem"
rowClasses="odd-row, even-row"
selection="#{crudBean.actionForm.selection}"
rows="#{crudBean.actionForm.occurrences}"
rowKeyVar="idx"
>
<a4j:ajax event="selectionchange"
listener="#{crudBean.actionForm.selectionListener}"
immediate="true" />
<rich:column width="100px" styleClass="#{rowItem.className}">
...stuff...
</rich:column>
<rich:column width="173px" styleClass="#{rowItem.className}">
...stuff...
</rich:column>
</rich:extendedDataTable>
The following code made sure the even got fired on row selection change:
<a4j:ajax event="selectionchange"
listener="#{crudBean.actionForm.selectionListener}"
immediate="true" />
The bean:
public void selectionListener(AjaxBehaviorEvent event) {
UIExtendedDataTable currentDataTable = (UIExtendedDataTable) event.getComponent();
Object originalKey = currentDataTable.getRowKey();
// debug log statement
log.debug("selectionListener() - rowKey = {} ", originalKey);
// debug log statement
if (log.isDebugEnabled()) {
log.debug("\n selectionListener() - rowIndex = {}", currentDataTable.getRowIndex());
}
if (currentDataTable.isRowAvailable()) {
// selectionItems.add(dataTable.getRowData());
IDataRow rowValue = transform((IDataGridRow)currentDataTable.getRowData());
changeActiveRow(rowValue);
}
}

To get the row number of the selected primefaces datatable row

I have a primefaces datatable i need to display (selected row number) of (total number of rows) in the JSF page.I could get the row numbers displayed in one of the columns using rowIndexVar attribute but i am not getting any idea to display the same numbers separately in the input text on row select.
What should i need to do in JSF page or managed bean to get selected row number.
Please help me in this regard.
Below is my JSF page
<p:dataTable id="workSpaceList" var="data"
value="#{workSpaceBean.lpInfoList}" widgetVar="multiSelection"
selection="#{workSpaceBean.selectedRows}" resizableColumns="true"
liveScroll="true" scrollRows="55" scrollWidth="85%"
scrollHeight="81%" styleClass="datatable"
scrollable="true" rowIndexVar="rowIndex"
filteredValue="#{workSpaceBean.filteredWorkSpaceItems}">
<p:column selectionMode="multiple" style="width:3%" />
<p:column headerText="#" style="width:3%">
#{rowIndex+1}
</p:column>
<p:column headerText="Insured" filterBy="#{data.insuredName}"
sortBy="#{data.insuredName}" style="width:24%">
<h:outputText value="#{data.insuredName}" />
<!-- style="width:250px" -->
</p:column>
<p:column headerText="City" filterBy="#{data.custAddress_City}"
sortBy="#{data.custAddress_City}" style="width:12%">
<h:outputText value="#{data.custAddress_City}" />
</p:column>
.
.
.
.
</p:dataTable>
I believe that there's not a straight forward way to do so. Although using two ajax requests is not pretty, you can at least achieve the result you expect when using plain PrimeFaces. You can reduce this to one call if you replace the p:ajax with the PrimeFaces extensions pe:javascript which does not do a roundtrip to the server
Every row (tr) rendered by your datatable has a attribute called data-rk with your rowKey and another attribute called data-ri with your rowIndexVar value.
You can get the data-rk attribute through dtWidgetVar.selection (dtWidgetVar is the name of the widgetVar in your datatable).
You can now send the indexRow to your model using a remoteCommand
Here is the code I used to test it:
The View
<p:remoteCommand name="displayIndex" process="#this" update="index" actionListener="#{viewMBean.displayRowIndex}"/>
<p:dataTable id="dt" var="data"
value="#{viewMBean.dataModel}"
selection="#{viewMBean.selectedRow}"
selectionMode="single"
widgetVar="dtVar"
rowIndexVar="index">
<p:ajax event="rowSelect"
oncomplete="displayIndex([{name:'index', value:jQuery('tr[data-rk=' + dtVar.selection + ']').attr('data-ri')}])" process="#this" />
<p:column headerText="#">
#{index + 1}
</p:column>
<p:column headerText="Dados">
#{data.name}
</p:column>
</p:dataTable>
<br />
Row Index: <p:inputText id="index" value="#{viewMBean.index}" />
Managed Bean
public void displayRowIndex() {
FacesContext context = FacesContext.getCurrentInstance();
Map map = context.getExternalContext().getRequestParameterMap();
String pIndex = (String) map.get("index");
index = Integer.parseInt(pIndex);
}
In case you are using checkbox selection, you can retrieve the selected indexes like this:
function beforeDisplayingIndexes(){
var indexes = "";
jQuery("tbody .ui-chkbox-box").each(function(){
if (jQuery(this).hasClass("ui-state-active")){
indexes = indexes + (indexes === "" ? "" : ",") + jQuery(this).closest("tr").attr("data-ri");
}
});
//for debuging only
console.log(indexes);
displayIndex([{name:'index', value:indexes}])
}
You should now be able to make the proper modification to your code to make use of that.
I'm surprised by the complex solution in the other answer. Assuming you you have the #{workSpaceBean.lpInfoList} serverside when doing the 'select', you can easily do (code according to the PrimeFaces showcase, adapt according to your needs)
<p:ajax event="rowSelect" listener="#{dtSelectionView.onRowSelect}" update="..." />
public void onRowSelect(SelectEvent event) {
int rownum = cars.indexOf((Car)event.getObject());
}

PrimeFaces - Dynamic menuItem

Considering the following code, it displays a table with one column and a filter to display the active/inactive records.
How can I disable the menuitem 'Inactive' based on the value selected in the filter? In other words if the the filter value is 'inactive', the 'Inactivate' menu should be disabled.
<p:contextMenu for="ratingScaleTable" id="RsContextMenuId">
<p:menuitem value="Edit" update=":templateForm:tabView, :templateForm:dirtyFlag" icon="ui-icon-search" action="#{ratingScaleBK.edit}" />
<p:menuitem id="inactivate" value="Inactivate" icon="ui-icon-close" action="#{ratingScaleBK.inactivate}" disabled="#{ratingScaleBK.selectedRatingScale.active==0}" />
<p:menuitem value="Activate" update=":templateForm:tabView" icon="ui-icon-close" action="#{ratingScaleBK.activate}"/>
<p:menuitem value="View Archive" update=":templateForm:tabView" icon="ui-icon-close"/>
</p:contextMenu>
<p:dataTable id="ratingScaleTable" widgetVar="tableWidget"
value="#{ratingScaleBK.ratingScaleList}" var="item1"
selectionMode="single"
selection="#{ratingScaleBK.selectedRatingScale}"
rowKey="#{item1.name}"
rendered="#{not empty ratingScaleBK.ratingScaleList}"
filteredValue="#{ratingScaleBK.filteredRatingscale}">
<p:ajax event="rowSelect" process="ratingScaleTable" listener="#{ratingScaleBK.edit}" update=":templateForm:tabView, :templateForm:dirtyFlag, :templateForm:tabView:RsContextMenuId " />
<p:column id="activeCol" filterBy="#{item1.active}"
filterOptions="#{ratingScaleBK.activeOptions}"
filterMatchMode="exact" width="30">
<h:outputText value="#{item1.active}" />
</p:column>
</p:dataTable>
Right now this code doesn't work, the contextMenu is never updated on rowSelect (the menu item 'Inactive' is always enabled). I guess the right click event on a specific row to display the menu doesn't really trigger the rowSelect event even if the row gets highlighted.
What is the proper way to do that?
I ended up using this solution from PF forum:
<p:contextMenu for="ratingScaleTable" id="RsContextMenuId" widgetVar="ctxMenu" beforeShow="return true;">
<p:dataTable id="ratingScaleTable" widgetVar="tableWidget"
...
<p:ajax event="rowSelect" process="ratingScaleTable" listener="#{ratingScaleBK.edit}" update=":templateForm:tabView, :templateForm:dirtyFlag, :templateForm:tabView:RsContextMenuId" />
<p:ajax event="contextMenu" update=":templateForm:tabView:RsContextMenuId" oncomplete="ctxMenu.show(currentEvent);"/>
and the associated JavaScript:
<script type="text/javascript">
var currentEvent;
$(document).ready(function() {
PrimeFaces.widget.ContextMenu.prototype.show = function(e) {
//hide other contextmenus if any
$(document.body).children('.ui-contextmenu:visible').hide();
if(e) {
currentEvent = e;
}
var win = $(window),
left = e.pageX,
top = e.pageY,
width = this.jq.outerWidth(),
height = this.jq.outerHeight();
//collision detection for window boundaries
if((left + width) > (win.width())+ win.scrollLeft()) {
left = left - width;
}
if((top + height ) > (win.height() + win.scrollTop())) {
top = top - height;
}
if(this.cfg.beforeShow) {
this.cfg.beforeShow.call(this);
}
this.jq.css({
'left': left,
'top': top,
'z-index': ++PrimeFaces.zindex
}).show();
e.preventDefault();
};
});
</script>
Try it with the contextMenu event:
<p:contextMenu for="ratingScaleTable" id="RsContextMenuId" widgetVar="ctxMenu">
...
</p:contextMenu>
<p:dataTable ... >
...
<p:ajax event="contextMenu" process="ratingScaleTable" listener="#{ratingScaleBK.edit}" update=":templateForm:tabView, :templateForm:dirtyFlag, :templateForm:tabView:RsContextMenuId" oncomplete="PF('ctxMenu').show();" />
...
</p:dataTable>

PrimeFaces dataTable scrollbar at desired position

I have a scrollable dataTable with 100+ records when I add a new record (outside the default viewable area)and update the datatable the dataTable gets loaded from record 0, whereas I need datatable view at the previous position.
My dataTable code
<p:dataTable id="DataTable" value="#{dtMB.selectDataModel}" var="test" scrollable="TRUE" scrollHeight="500" styleClass="day-column2" selectionMode="single" >
<ui:insert name="TableInsert" >
<ui:include src="test.xhtml" />
</ui:insert>
</p:dataTable>
Command Button (inside a dialog) which updates the Datatable
<p:commandButton id="saveNew" value="Save" type="submit" process="#parent" onsuccess="addNew.hide()" action="#{dtMB.addNew()}" update=":FORM:usrMsg :FORM:TABView:DataTable"/>
currently I need to scroll back to the n'th record to see what was added or do any updates etc.
Is there any option in primeface datatable, or I need to write a javascript for the same.
I did the above using the following post
primeface datatable scrollbar position
datatable scroll
my code
script
function saveScrollPos() {
var scrollPos = jQuery('#receptionFORM\\:receptionTV\\:scheduleDataTable .ui-datatable-scrollable-body').prop('scrollTop');
document.getElementById('receptionFORM:scrollPos').value = scrollPos;
}
function autoScroll() {
var scrollPos = document.getElementById('receptionFORM:scrollPos').value;
jQuery('#receptionFORM\\:receptionTV\\:scheduleDataTable .ui-datatable-scrollable-body').animate({scrollTop:scrollPos}, scrollPos);
}
HiddenInput
<h:inputHidden id="scrollPos" />
In Ajax event of datatable row select
onstart="saveScrollPos()"
The below code in CommandButton while saving record
oncomplete="autoScroll()"

How can I get geocoder address to backing bean?

Using PrimeFaces p:gmap component.
I have a page with a gmap component with a set of markers.
I want to display the street address in the gmapInfoWindow and pass it to the backing bean as well.
When I click on the map marker, I call a javascript function to get the reverse geocoder address.
I can fetch the address and display it in a javascript alert dialog, but I can't get it to fill the backing bean variable or in the info marker.
The variable does get filled, but it does not get updated until the next time I click on the marker.
As a result, the addresses are always one marker click behind.
Does anyone know how I can get the address to update during the current page session?
Thanks.
The backing bean code onMapMarkerSelect just has a System.out.println statement to show the mapAddress variable.
Here is the page code:
<h:form prependId="false" >
<p:gmap id="gmap" center="#{mappingSessionBean.mapCenter}" zoom="#{mappingSessionBean.mapZoom}" type="HYBRID" rendered="true"
style="#{mappingSessionBean.polygonGmapStyle}" onPointClick="handlePointClick(event);"
model="#{mappingSessionBean.mapModel}" fitBounds="#{mappingSessionBean.fitBoundsFlag}"
widgetVar="map" >
<p:ajax id="gmapAjax" event="overlaySelect" immediate="true" onstart="handlePointClick(event);" listener="#{mappingSessionBean.onMapMarkerSelect}" />
<p:gmapInfoWindow id="infoWindow" >
<p:outputPanel >
<h:panelGrid columns="1" >
<h:outputText id="infoWindowTitle" value="#{mappingSessionBean.selectedMarker.title}" />
<h:outputText id="infoWindowAddress" value="#{mappingSessionBean.mapAddress}" rendered="true" />
<p:commandButton value="Zoom In" action="#{mappingSessionBean.selectedViewInfoListener}" update="gmap" />
</h:panelGrid>
</p:outputPanel>
</p:gmapInfoWindow>
</p:gmap>
<h:inputHidden id="address" value="#{mappingSessionBean.mapAddress}" />
</h:form >
<script type="text/javascript" >
function handlePointClick(event) {
if(navigator.geolocation)
{
browserSupportFlag = true;
var latlng = event.latLng;
geocoder = new google.maps.Geocoder();
geocoder.geocode({'latLng': latlng}, function(results, status)
{
if( status == google.maps.GeocoderStatus.OK )
{
alert( results[0].formatted_address );
document.getElementById('address').value = results[0].formatted_address;
document.getElementById('infoWindowAddress').value = results[0].formatted_address;
}
else
{
alert( "Geocoder failed due to: " + status );
}
});
}
else
{
alert( "No Geolocation");
}
}
</script>
Here is a general solution, I guess you can do better if you will find a way to trigger an event on inputHidden without the use of the button
b.t.w : jQuery comes with primefaces so you can use it without any additional includes
instead of
<h:inputHidden id="address" value="#{mappingSessionBean.mapAddress}" />
place
<f:ajax listener="#{mappingSessionBean.myajax}" execute="address">
<h:inputHidden id="address" value="#{mappingSessionBean.mapAddress}" />
<h:commandButton id="addressBtn" style="display:none"/>
</f:ajax>
(you can replace execute="address" with execute="#form")
and in js code replace
document.getElementById('address').value = results[0].formatted_address;
with
jQuery("#address").val(results[0].formatted_address);
jQuery("#addressBtn").click(); // this will trigger the ajax listener
and finally in your bean add the implementation of the ajax listener itself
public void myajax(AjaxBehaviorEvent event) {
System.out.println(getMapAddress());
}

Resources