Change DataTable row color on checkbox selection - primefaces

I have a <p:dataTable> , with a checkbox on the last column. I want to color the rows of the table based on the status of the checkbox.
<p:dataTable var="acs" value="#{myBean.listaRevogaveis}"
emptyMessage="#{rotulo.mensagemSemDados}" paginator="true"
rows="10" id="tableacs"
paginatorTemplate="{CurrentPageReport} {FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink}">
<p:column headerText="Nome" sortBy="#{acs.nome}"
filterBy="#{acs.nome}">
<h:outputText value="#{acs.nome}" />
</p:column>
<p:column headerText="Address" sortBy="#{acs.address}" filterMatchMode="contains"
filterBy="#{acs.address}" filterMaxLength="8">
<h:outputText value="#{acs.address}" />
</p:column>
<p:column headerText="Perfil" sortBy="#{acs.cdPerfil}"
filterBy="#{acs.cdPerfil}" filterMaxLength="2">
<h:outputText value="#{acs.cdPerfil}" />
</p:column>
<p:column headerText="Cadastramento">
<h:outputText value="#{acs.tsSolicitacao}">
<f:convertDateTime pattern="dd/MM/yyyy" />
</h:outputText>
</p:column>
<p:column headerText="Concedido">
<h:outputText value="#{acs.concedidoPor}" />
</p:column>
<p:column headerText="Revogar">
<p:selectBooleanCheckbox value="#{acs.ativo}" >
<p:ajax event="valueChange" oncomplete="toggleColor(this, #{acs.ativo}" listener="#{myBean.checkBox}" update="#form"/>
</p:selectBooleanCheckbox>
</p:column>
</p:dataTable>
So on the toggling of #{acs.ativo} I want that row to receive a different background color.
Following the answer of this question I tried to add this to my xhtml:
<style type="text/css">
.linhaDestacada { background-color: red !important;}
</style>
<script type="text/javascript">
function toggleColor(col, status) {
var linha = jQuery(col).parent();
if(status) {
linha.removeClass('linhaDestacada');
} else {
linha.addClass('linhaDestacada');
}
}
</script>
But that's of no use. I put some alerts to see if the function was being called, it is. However, trying to see the tagName, or any property of the linha variable returns null.
There is another interesting point, the callback is being called with the previous value of the checkbox. When box is checked, javascript toggleColor() is receiving false on the status, when its unchecked it receives true.
How can I make the row background toggle together with the checkbox toggle?

Ok, there were a TON of bugs and problems in that one.
First:
primefaces sets the background of the rows to a blank image (depending on the skin). you have to override the url() of the background, so the CSS should look like:
.linhaDestacada { background: url('') red !important;}
Second:
Calling the javascript from the ajax tag was causing the jQuery to find nulls (dunno why). move the callback to the checkbox tag, using its onchange attribute.
The final javascript fragment was:
<script type="text/javascript">
function toggleColor(col, status) {
var linha = jQuery(col).parent().parent().parent().parent().parent();
if(status) {
linha.removeClass('linhaDestacada');
//alert("remove " + linha.html());
} else {
linha.addClass('linhaDestacada');
//alert("add " + linha.html());
}
}
</script>
Third:
Updating the WHOLE form is a no-no (the css class you added with javascript was being erased)... you should update only what really matters (in this case, the checkbox and the command button.
<p:selectBooleanCheckbox value="#{acs.ativo}" onchange="toggleColor(this, #{acs.ativo})">
<p:ajax event="valueChange" listener="#{myBean.checkBox}" update="#this :formAcesso:btnRevogaNuke" />
</p:selectBooleanCheckbox>
Fourth:
the commandButton was not rendering. It would be updated on the ajax response, but the browser did not display it. Found this answer, and moved the id btnRevogaNuke on the encapsulating element:
<h:panelGroup id="btnRevogaNuke" layout="block">
<p:commandButton icon="ui-icon-alert" value="Confirmar rendered="#{myBean.confirmar()}" style="margin-left:600px;" action="#{acessoBean.revogaTodos()}" process="#this #form" update="#form" />
</h:panelGroup>

Related

Set focus on input text with PrimeFaces

I currently have an .xhtml that shows a pop up depending on some events in JAVA, now i need that if the pop up shows put the focus on a expecific textfield.
JAVA
public void validate(){
if(List.size()>0){
String [] codes = {"1","97","119","606","695","700","738","730"};
List<String> codesList = Arrays.asList(codes);
String coomentsString ="THIS IS A STRING";
if(codesList.contains(List.get(0).getCode())){
MessageUtil.addInfoMessage(LabelKeys.DOCBR_INFO,coomentsString);
PrimefacesUtil.showMessage();
}
}
}
XHTML
<p:commandButton id="loadPage" action="#CLASS.validate}"/>
<p:inputText id="comments"/>
<script type="text/javascript">
$( document ).ready(function() {
var name= document.getElementById('containerForm:loadPage');
name.click();
});
</script>
XHTML POP UP
<p:dialog id="growl" widgetVar="messagePopupWidget" resizable="false"
modal="true" width="270px" styleClass="messagedialog">
<p:ajax event="close" update="growl"
listener="#{messageDialog.handleCloseDialogMessageEvent}" />
<p:panelGrid style="width:100%;">
<p:row>
<p:column style="text-align:left;">
<p:messages showSummary="true" showDetail="true"
autoUpdate="false" escape="false"/>
</p:column>
</p:row>
<p:row>
<p:column style="text-align:center;">
<p:commandButton id="messageDialogButtonId" value="#{label['messageDialog.btn.ok']}" onclick="messagePopupWidget.hide();" update="growl" type="button"/>
</p:column>
</p:row>
</p:panelGrid>
</p:dialog>
now, i need that after loadPage makes the click on javascript and shows the pop up from validate(), put the cursor on "comments"
Two ways to achieve this with primefaces:
1. Include this in your dialog to set explicit focus
<p:focus for="commentsID"/>
There is an onShow attribute on the dialog, you can use that to set the focus manually
<p:dialog id="loadPage"
onShow="document.getElementById("commentsID").focus();"/>

Primefaces SelectOneMenu reselect option in deleted row within DataTable in new row

I have a selectonemenu within a datatable column. The selected options are messed up when I delete a row and it doesn't seems to reflect the value in the backend bean. For example, I selected Item A in the first row, then add another row and select Item B in the second row, then when I delete the first row, the second row is move up with Item A selected, but the backend value of second row is still Item B and Item A is removed from the collection.
<p:dataTable id="insertDetailTable" styleClass="data-table"
rowIndexVar="rowIndex" var="receivingDetail"
value="#{receivingController.receiving.receivingDetails}">
<p:column headerText="Item">
<p:selectOneMenu styleClass="input" id="item"
value="#{receivingDetail.item}" required="true"
requiredMessage="Item is required" converter="itemConverter">
<f:selectItem itemLabel="Select an item" itemValue="#{null}"
noSelectionOption="true" />
<f:selectItems value="#{receivingController.items}" var="item"
itemLabel="#{item.code} - #{item.name}" itemValue="#{item}" />
<p:ajax update="insertDetailTable" />
</p:selectOneMenu>
</p:column>
<p:column styleClass="action-cell">
<f:facet name="header">
<p:commandButton icon="ui-icon-plus" value="Add"
action="#{receivingController.insertDetail('insert')}"
immediate="true" />
</f:facet>
<p:commandButton icon="ui-icon-trash"
action="#{receivingController.deleteDetail('insert', receivingDetail)}"
immediate="true">
<p:confirm header="Confirmation"
message="Do you wish to remove the selected detail?"
icon="ui-icon-alert" />
</p:commandButton>
</p:column>
</p:dataTable>
The backend code of adding a new row and deleting a row:
public void insertDetail(String owner) {
ReceivingDetail receivingDetail = new ReceivingDetail();
receivingDetail.setReceiving(receiving);
receivingDetail.setQtyStored(new BigDecimal("0.00"));
receiving.getReceivingDetails().add(receivingDetail);
RequestContext context = RequestContext.getCurrentInstance();
if (owner.equals(OWNER_INSERT)) {
context.update("insertForm");
context.execute("PF('insertDialogWV').show();");
} else if (owner.equals(OWNER_UPDATE)) {
context.update("updateForm");
context.execute("PF('updateDialogWV').show();");
}
}
public void deleteDetail(String owner, ReceivingDetail receivingDetail) {
receiving.getReceivingDetails().remove(receivingDetail);
ItemService itemSvc = (ItemService) getService(ItemService.class);
setItems(itemSvc.find());
RequestContext context = RequestContext.getCurrentInstance();
if (owner.equals(OWNER_INSERT)) {
context.update("insertForm");
context.execute("PF('insertDialogWV').show();");
} else if (owner.equals(OWNER_UPDATE)) {
context.update("updateForm");
context.execute("PF('updateDialogWV').show();");
}
}
Any idea what went wrong with my code?
I am using Primefaces 5 and JSF 2.2.
This is the first time I posting a question, not sure did I do it right, let me know if I need to correct anything, thanks in advance.
Edited:
Just in case this information is required, the datatable resides within a dialog as such.
<h:form id="insertForm">
<p:dialog id="insertDialog" widgetVar="insertDialogWV" modal="true"
draggable="false" resizable="false" header="Add Record"
closable="false">
</p:dialog>
</h:form>
Removed immediate="true" in the command button and it works, the table select and show the value according to the backend bean properly.

How to use the same datatable for all the tabs primefaces (resize not working in this case)

I am using primefaces 5.3 and jsf 2.2.6.
I have created two static tabs to see if it works to use the same xhtml page (transactionsPage) that contains a datatable.
These are the tabs:
<h:form id="formTabs">
<p:tabView id="tabs" activeIndex="#{mainPage.index}">
<p:ajax event="tabClose" listener="#{mainPage.remove}" update="formTabs" />
<p:ajax event="tabChange" listener="#{mainPage.changeTab}" update="formTabs" />
<p:tab id="transAssembling" title="ASSEMBLING" closable="true">
<f:subview id="tab0">
<ui:include src="transactionsPage.xhtml">
<ui:param name="status" value="ASSEMBLING" />
<ui:param name="columnList" value="#{tabs.list[0].columnList}" />
</ui:include>
</f:subview>
</p:tab>
<p:tab id="transPrinting" title="PRINTING" closable="true">
<f:subview id="tab1">
<ui:include src="transactionsPage.xhtml">
<ui:param name="status" value="PRINTING" />
<ui:param name="columnList" value="#{tabs.list[1].columnList}" />
</ui:include>
</f:subview>
</p:tab>
</p:tabView>
</h:form>
I used the subView, in order to have different ids for the datatable from the included transactionsPage.xhtml, so that I can use the same xhtml page for all tabs and only change the columns and data, that are calculated in the managed bean of the transactionsPage.xhtml.
So for the datatable
from the first tab: the absolute path would be
formTabs:tabs:tab0:transactionsTable
from the second tab: the absolute path would be
formTabs:tabs:tab1:transactionsTable
This is the datatable from the transactionsPage:
<p:dataTable id="transactionsTable" var="data" value="#{transactionsPage.ttList}" widgetVar="projectData"
rowKey="#{data.id}"
draggableColumns="true"
draggableRows="true"
resizableColumns="true" emptyMessage="#{msg['form.noTransactionsFound']}" rows="20"
selectionMode="single" selection="#{transactionsPage.selectedTransaction}"
filteredValue="#{transactionsPage.fitleredttList}" paginator="true" paginatorPosition="both" paginatorTemplate="{CurrentPageReport} {RowsPerPageDropdown} {FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink}"
>
<p:ajax event="colResize" listener="#{transactionsPage.onColumnResize}" update="transactionsTable"/>
<f:ajax event="rowSelect" render="formTabs"/>
<!-- Stiky does not work with column filtering paginator="true" paginatorPosition="bottom" paginatorTemplate="{CurrentPageReport} {RowsPerPageDropdown} {FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink} " stickyHeader="true" -->
<f:facet name="header">
<p:outputPanel styleClass="mainPageProjectsTableHeader" >
<h:outputText value="#{msg['form.searchAllFields']}" style="float:left; margin-right:10px;"/>
<p:inputText id="globalFilter" onkeyup="PF('projectData').filter()" style="width:150px; float:left" placeholder=" #{msg['form.enterKeyword']}"/>
<p:commandButton id="toggler" type="button" value="#{msg['form.columns']}"
styleClass="columnSelector" icon="ui-icon-calculator" />
<p:columnToggler datasource="transactionsTable" trigger="toggler" >
<p:ajax event="toggle" listener="#{transactionsPage.onToggle}" />
</p:columnToggler>
</p:outputPanel>
</f:facet>
<c:forEach var="column" items="#{transactionsPage.columnList}">
<p:column id="#{column.id}" filterStyleClass="#{column.filterStyleClass}" headerText="#{column.title}" visible="#{column.visible}" width="#{column.width}" filterBy="#{data[column.property]}" filterMatchMode="contains" styleClass="mainPageCompanyColumn">
<f:attribute name="rtcCol" value="#{column}"/>
<h:outputText value="#{data[column.property]}" />
</p:column>
</c:forEach>
</p:dataTable>
The problem is the following:
When I want to resize a column in the last opened tab, it works and I see that before calling the resize method from the managed bean, a queueEvent method from the primefaces Datatable.class is called(in this method it takes the decision which event to call), in which the clientId is correct formTabs:tabs:tab1:transactionsTable and then the resize method is being called.
But when I go in another tab, the clientId from the queueEvent method remains the same, from the last tab openend formTabs:tabs:tab1:transactionsTable and I get the following exception, so that the resize method is not be called anymore.
java.lang.NullPointerException
at org.primefaces.component.datatable.DataTable.findColumnInGroup(DataTable.java:909)
at org.primefaces.component.datatable.DataTable.findColumn(DataTable.java:900)
at org.primefaces.component.datatable.DataTable.queueEvent(DataTable.java:814)
at org.primefaces.behavior.ajax.AjaxBehaviorRenderer.decode(AjaxBehaviorRenderer.java:47)
at javax.faces.component.behavior.ClientBehaviorBase.decode(ClientBehaviorBase.java:132)
at org.primefaces.renderkit.CoreRenderer.decodeBehaviors(CoreRenderer.java:530)
at org.primefaces.component.datatable.DataTableRenderer.decode(DataTableRenderer.java:66)
I assume this happens, because of the clientId of the datatable, which is not updated to the datatable from the tab, where I have changed the focus on.
So the question would be: How could I change the whole path/id to the newly opened tab/datatable:
formTabs:tabs:tab0:transactionsTable
because my assumption is that that's why the resize method is not being called for another tab then the last opened tab.
If it's not clear enough or the architecture is bad, then the question would be
How to use the same xhtml page/datatable for 11 tabs without creating 11 static datatables?
So, it seemed that the problem was the widgetVar from the datatable, because it was used the same value for the widgetVar for every single datatable and that's why it had the same clientId, because the same clientId was added to the DOM.
If you want to read about the widgetVar:
http://blog.hatemalimam.com/intro-to-primefaces-widgetvar/
So, as a conclusion, I have set dynamically a value to the widgetVar for each tab and the clientId in the primefaces Datatable class was correct,the resize method was called and it worked.

commandlink primefaces with href

i'm trying to open a popup mailto by using two different codes:
(1)- <p:link href="mailto:#{classManagedBean.sendEmails}" />
(2)- <p:commandlink actionListener="#{candidatManagedBean.sendEmails()}" />
the "senEmails" is a method declared in the classManagedBean in order to get all the selected emails when a submit of the form done.
The issus that i encountred that when:
working with the code (1) the selected mails came to the managedBean with null values and a popup of the mail interface open with empty mails (as destination)
with the code (2) the selected mails came with the correct values but the popup didn't appear (beacause there is no href attribut!! in the commandLink)
My question is how can i use a
<p:link> with a submit form
<p:commandLink> with href attribut
The Xhtml:
<h:form id="form">
<p:link href="#{candidatManagedBean.createmaito()}">
<p:graphicImage width="25" value="ecrire.png" height="25" alt="envoyer"/>
</p:link>
</h:form>
<p:dataTable id="listCandidat"
value="#{candidatManagedBean.listCandidat}"
emptyMessage="0 candidat trouvé"
var="item"
paginator="true" rows="15" paginatorPosition="bottom"
rowKey="#{item.idCandidat}"
paginatorTemplate="{FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink}"
lazy="true"
selection="#{candidatManagedBean.selectedCandidates}"
>
<p:ajax event="rowSelect" listener="#{candidatManagedBean.onRowSelect}" />
<p:column exportable="false" selectionMode="multiple" style="width:16px;text-align:center"/>
{<p:column>...</p:column>}
</p:dataTable>
The managedBean:
public String createmaito() { // private List<Candidat> selectedCandidates;
System.out.println(selectedCandidates);//here i got a null value of selectedCandidates
if (selectedCandidates != null && !selectedCandidates.isEmpty()) {
for (Candidat cand : selectedCandidates) {
lsEmail = lsEmail.concat(cand.getEmail1());
lsEmail = lsEmail.concat(",");
}
lsEmail= lsEmail.substring(0, lsEmail.length()-1);
result = lsEmail;
}
else {
result = "";
}
return result;
}
I got the solution as follows:
-In XHTML:
<p:commandLink actionListener="#{ManagedBean.getListeOfEmailContacts()}">
<p:graphicImage value="/mail.png" />
</p:commandLink>
-In managed bean:
public void getListeOfEmailContacts() {
/* instruction to get the ListOfContacts ...*/
RequestContext.getCurrentInstance().execute("window.open(href ='mailto:" + ListOfContacts + "')");
}

Adding p:outputLabel for multiple required fileds inside datatable / datagrid

I have simple Primefaces DataTable , inside this DataTable I have a p:outputLabel , I need the for attribute to point multiple inputFields, how I can do it ?
Sample code :
<p:dataTable var="car" value="#{mbBasicView.cars}">
<p:column headerText="Id">
<p:outputText value="#{car.name}" />
</p:column>
<p:column headerText="Year">
<p:inputText id="carYear" value="#{car.year}" />
</p:column>
<p:column headerText="Brand">
<h:inputText id="carPrice" value="#{car.price}" />
</p:column>
</p:dataTable>
I want to point car name to year and price, if user not entered the year or / and price, it must rise an required validation message, with highlight (and add start) to car name.
I have found workaround for this issue, with CSS and adding extra label, this maybe helpful for panelGrid also (I think anything inside <p:column>) , But I tested it with DataTable only:
<p:dataTable var="car" value="#{mbBasicView.cars}">
<p:column headerText="Id">
<p:outputText styleClass="car-name" for="carYear" value="#{car.name}" />
<p:outputText styleClass="car-name" for="carPrice" value="#{car.name}" />
</p:column>
<p:column headerText="Year">
<p:inputText id="carYear" value="#{car.year}" />
</p:column>
<p:column headerText="Brand">
<h:inputText id="carPrice" value="#{car.price}" />
</p:column>
</p:dataTable>
And css style that hide filed if another is error state or duplicated:
.car-name {
display:none;
}
.car-name.ui-state-error {
display:block;
}
.car-name ~ .car-name {
display:block;
}
.car-name ~ .car-name.ui-state-error {
display:block;
}
.car-name.ui-state-error ~ .car-name{
display:none;
}
Hope this will be helpful, in case you have more than 2 fields it will work except if you have 2 normal labels then error label, I think you can play around this case with another style class, play around the CSS magic will do awesome work.