Null value in the first itemUnselect event on primefaces autoComplete - primefaces

I am facing a strange situation when using primefaces p:autoComplete. I put this piece of code in a xhtml file, inside a h:form tag:
<p:autoComplete id="to"
multiple="true"
value="#{editEmailComponent.receiversEntitiesToDummy}"
completeMethod="#{editEmailComponent.completeQuery}"
emptyMessage="#{text['list.empty']}"
var="ent"
itemLabel="#{ent.class.simpleName eq 'EntityGroupHeader'? ent.design : (ent.class.simpleName eq 'EntityContactList'? ent.email : ent.abstractEntityEmail)}"
itemValue="#{ent}"
forceSelection="true"
cache="false"
styleClass="full-width"
autocomplete="none">
<o:converter converterId="omnifaces.ListConverter"
list="#{editEmailComponent.receiversAllConverter}" />
<p:column>
<h:outputText rendered="#{(ent.class.simpleName ne 'EntityGroupHeader') and (ent.class.simpleName ne 'EntityContactList')}" value="\# #{ent.number}" />
<h:outputText rendered="#{ent.class.simpleName eq 'EntityGroupHeader'}" value="\# #{ent.design}" />
<h:outputText rendered="#{ent.class.simpleName eq 'EntityContactList'}" value="#{ent.nif}" />
</p:column>
<p:column>
<h:outputText rendered="#{(ent.class.simpleName ne 'EntityGroupHeader') and (ent.class.simpleName ne 'EntityContactList')}" value="#{ent.abstractEntityDesignation}" />
<h:outputText rendered="#{ent.class.simpleName eq 'EntityContactList'}" value="#{ent.designation}" />
</p:column>
<p:column>
<h:outputText rendered="#{(ent.class.simpleName ne 'EntityGroupHeader') and (ent.class.simpleName ne 'EntityContactList')}" value="#{ent.abstractEntityEmail}" />
<h:outputText rendered="#{ent.class.simpleName eq 'EntityContactList'}" value="#{ent.email}" />
</p:column>
<p:ajax event="query" process="#this"/>
<p:ajax event="itemSelect" process="#form" listener="#{editEmailComponent.onItemSelectTo}" update="to" />
<p:ajax event="itemUnselect" process="#form" listener="#{editEmailComponent.onItemUnselectTo}" update="to" />
</p:autoComplete>
The action associated to this itemUnselect event is:
public void onItemUnselectTo(UnselectEvent event) {
onItemUnselect(receiversEntitiesToDummy, event);
BaseObject obj2 = (BaseObject) event.getObject();
//Instancia da entidade e converter para receiver
if(obj2 instanceof EntityContactList){
EntityContactList aux = (EntityContactList) obj2;
for(Receiver rec : receiversTo)
if(rec.getEntity().equals(aux.getEntity()))
receiversTo.remove(rec);
}
private static void onItemUnselect(List<BaseObject> list, UnselectEvent event) {
BaseObject obj = (BaseObject) event.getObject();
list.remove(obj);
}
I initialize the list of this autocomplete like this:
private List<BaseObject> receiversEntitiesToDummy = new ArrayList<>();
...
EntityContactList result = entityManager.getEntityContactList(receiver.getEntity(),null);
receiversEntitiesToDummy.add(result);
So, when I remove this first element the "obj2" is null but when I search and select some object the "obj2" is properly filled. Anyone knows why this happens?
Note: I am using primefaces 5.2.

I solved my problem changing the way I populate the list with the first element.
Instead of this:
private List<BaseObject> receiversEntitiesToDummy = new ArrayList<>();
...
EntityContactList result = entityManager.getEntityContactList(receiver.getEntity(),null);
receiversEntitiesToDummy.add(result);
I put the first element using the query function and it works.
EntityContactList result = entityManager.getEntityContactList(receiver.getEntity(),null);
List<BaseObject> aux = new ArrayList<>();
if(receiver.getEntity().getAbstractEntityEmail() != null)
aux = completeQuery(receiver.getEntity().getAbstractEntityEmail());
if(aux.contains(result)){
int num = aux.indexOf(result);
EntityContactList another = (EntityContactList) aux.get(num);
receiversEntitiesToDummy.add(another);
}

Related

How to use "sortBy" in a p:dataTable with HashSet collection

UPDATED
I have the following dataTable:
<p:dataTable id="shipOwnerCompanyHistoriesTable" widgetVar="shipOwnerCompanyHistoriesTable" var="entry" value="#{shipRegisterView.ship.shipOwnerCompanyHistories}" rowKey="#{entry}" selectionMode="single" selection="#{shipRegisterView.selectedShipOwnerCompanyHistory}"
styleClass="margin-bottom-10" paginator="true" rows="5"
paginatorTemplate="{RowsPerPageDropdown} {FirstPageLink} {PreviousPageLink} {CurrentPageReport} {NextPageLink} {LastPageLink}"
rowsPerPageTemplate="5,10" emptyMessage="Δεν βρέθηκαν εγγραφές.">
<p:ajax event="rowSelect" update="#form" listener="#{shipRegisterView.selectShipOwnerCompanyHistory}" />
<p:ajax event="rowUnselect" update="#form" listener="#{shipRegisterView.unselectShipOwnerCompanyHistory}" />
<p:column headerText="Πλοιοκτησία">
<h:outputText value="#{entry.company.brandNameGreek} / #{entry.company.brandNameLatin}"/>
</p:column>
<p:column headerText="Από" sortBy="#{entry.fromDate}">
<h:outputText value="#{entry.fromDate}">
<f:convertDateTime pattern="dd/MM/yyyy" />
</h:outputText>
</p:column>
<p:column headerText="Έως" sortBy="#{entry.toDate}">
<h:outputText value="#{entry.toDate}">
<f:convertDateTime pattern="dd/MM/yyyy" />
</h:outputText>
</p:column>
<p:column headerText="Ποσοστό" sortBy="#{entry.percentage}">
<h:outputText value="#{entry.percentage}%"/>
</p:column>
<p:column headerText="Σημειώσεις">
<h:outputText value="#{entry.comments}" rendered="#{entry.comments != null and not empty entry.comments}"/>
<h:outputText value="-" rendered="#{entry.comments == null or empty entry.comments}"/>
</p:column>
</p:dataTable>
With the value being taken from the follwoing view class like so:
public ShipRegisterView() {
newFlagHistory = new ShipFlagHistory();
lossState = "";
growlId = "shipMessages";
ship = new Ship();
ship.setLossState("Normal");
shipList = new ArrayList<Ship>();
newEncumbrance = new ShipEncumbrance();
newFek = new ShipFek();
newShipEngine = new ShipEngine();
newShipRenameHistory = new ShipRenameHistory();
newTransferHistory = new ShipTransferHistory();
newShipOwnerCompanyHistory = new ShipOwnerCompanyHistory();
newShipOwnerNaturalPersonHistory = new ShipOwnerNaturalPersonHistory();
newShipAdminCompanyHistory = new ShipAdminCompanyHistory();
newShipUtilizationCompanyHistory = new ShipUtilizationCompanyHistory();
newShipOwnerCompanyHistory.setCompany(new Company());
newShipOwnerNaturalPersonHistory.setNaturalPerson(new NaturalPerson());
newShipAdminCompanyHistory.setCompany(new Company());
newShipUtilizationCompanyHistory.setCompany(new Company());
newConditionHistory = new ShipConditionHistory();
newRecreationalLicense = new RecreationalLicense();
newRecreationalLicense.setAdminClassAct(new AdminClassAct());
newRecreationalLicense.setAdminDeclassAct(new AdminDeclassAct());
searchInspectionsList = new ArrayList<Inspection>();
searchCertificatesList = new ArrayList<Certificate>();
searchRosCertificatesList = new ArrayList<Certificate>();
searchAffirmationsList = new ArrayList<Affirmation>();
newNaturalPerson = new NaturalPerson();
newNaturalPerson.setAddress(new Address());
searchNaturalPerson = new NaturalPerson();
harboursForShipsForDNPUser = new ArrayList<Harbour>();
fines = new ArrayList<Fine>();
complaints = new ArrayList<Complaint>();
completedRoutes = new ArrayList<CompletedRoute>();
searchOwnerCompany = new SearchCompany();
searchOwnerNaturalPerson = new SearchNaturalPerson();
searchAdminCompany = new SearchCompany();
searchUtilizationCompany = new SearchCompany();
ship.setShipEngines(new HashSet<ShipEngine>());
ship.setShipAdminCompanyHistories(new HashSet<ShipAdminCompanyHistory>());
ship.setShipOwnerCompanyHistories(new HashSet<ShipOwnerCompanyHistory>());
ship.setShipOwnerNaturalPersonHistories(new HashSet<ShipOwnerNaturalPersonHistory>());
ship.setShipUtilizationCompanyHistories(new HashSet<ShipUtilizationCompanyHistory>());
ship.setShipEncumbrances(new HashSet<ShipEncumbrance>());
ship.setShipConditionHistories(new ArrayList<ShipConditionHistory>());
ship.setShipFeks(new HashSet<ShipFek>());
ship.setDocuments(new HashSet<AccompanyingFile>());
ship.setShipPhotos(new HashSet<ShipPhoto>());
ship.setShipFlagHistories(new HashSet<ShipFlagHistory>());
ship.setRecreationalLicenses(new HashSet<RecreationalLicense>());
ship.setShipTransferHistories(new HashSet<ShipTransferHistory>());
ship.setLossTheftDecisions(new HashSet<LossTheftDecision>());
ship.setShipRenameHistories(new HashSet<ShipRenameHistory>());
List<ShipOwnerCompanyHistory> list = new ArrayList<>(shipOwnerCompanyHistories);
};
The thing i am trying to do is to sort the columns of the table using the sortBy attribute of primefaces. When i press the column, i get the following error on the webpage:
And on my tomcat:
ERROR (com.liferay.faces.bridge.context.internal.ExceptionHandlerAjaxImpl.java:71).handle - Data type should be java.util.List or javax.faces.model.ListDataModel instance to be sortable.
Now, i understand that it has to be a list in order to work, but is there a way where i can sort the table? Hibernate mapping is a set too:
<set name="shipOwnerCompanyHistories" inverse="true" cascade="all-delete-orphan" lazy="false" >
<key column="shipId" on-delete="cascade"/>
<one-to-many class="gr.yptp.hcg.sr.Model.ShipOwnerCompanyHistory"/>
</set>
Let me know. I really appreciate your help.
Instead of
ship.setShipOwnerCompanyHistories(new HashSet<ShipOwnerCompanyHistory>());
and further on
List<ShipOwnerCompanyHistory> list = new ArrayList<>(shipOwnerCompanyHistories);
(where the list variable is nowhere used anymore, doesn't it have a yellow squirreled lin under it in your IDE?)
Do
ship.setShipOwnerCompanyHistories(new ArrayList<>(new HashSet<ShipOwnerCompanyHistory>()));
or just
ship.setShipOwnerCompanyHistories(new ArrayList<ShipOwnerCompanyHistory>());
or you you retrieved the shipOwnerCompanyHistories variable (assuming it is a HashSet from the database, do
ship.setShipOwnerCompanyHistories(new ArrayList<>(shipOwnerCompanyHistories));

p:datatable summary row calculation

I have a p:dataTable pretty similar to the showcase.
Unfortunatly, the showcase uses randomly generated values for the p:summaryRow.
Refering to the showcase, imagine the car had a price attribute.
How would I sum up the price for the cars grouped by the specified column for displaying it in the summary row?
I have same problem with you and found correct usage from primefaces blog
SummaryRow from primefaces forum
this is some example show correct calculation for sum price, count...
Listener gets the group property which is the sortBy value which you can use to calculate totals or any other operation.
<p:summaryRow listener="#{backingBean.calculateTotal}">
<p:column colspan="3" style="text-align:right">
Total:
</p:column>
<p:column>
#{backingBean.total}
</p:column>
</p:summaryRow>
/* listener method in your bean */
public void calculateTotal(Object o) {
this.total = 0.0d;
String name = "";
if(o != null) {
if(o instanceof String) {
name = (String) o;
for(MyRowObject p : (List<MyRowObject>) dataTableModel.getWrappedData()) { // The loop should find the sortBy value rows in all dataTable data.
switch(sortColumnCase) { // sortColumnCase was set in the onSort event
case 0:
if(p.getcolumn0data().getName().equals(name)) {
this.total += p.getcolumn0data().getValue();
}
break;
case 1:
if(p.getcolumn1data().getName().equals(name)) {
this.total += p.getcolumn1data().getValue();
}
break;
}
}
}
}
}
this is my solution:
<p:dataTable var="elem" value="#{unitSubStatusChart.resultList}" tableStyleClass="app-table-auto">
<et:defaultPaginator />
<p:column headerText="#{bundle['class']}" sortBy="#{elem.dtype}">
<e:outputIconText icon="#{icons[elem.dtype]}" value="#{bundle[elem.dtype]}" />
</p:column>
<p:column headerText="#{bundle['status']}" sortBy="#{elem.status}">
<h:outputText value="#{bundle[elem.status]}" />
</p:column>
<p:column headerText="#{bundle['subStatus']}" sortBy="#{elem.subStatus}">
<h:outputText value="#{bundle[elem.subStatus]}" />
</p:column>
<p:column headerText="#{bundle['count']}">
<h:outputText value="#{elem.count}" />
</p:column>
<p:summaryRow listener="#{unitSubStatusChart.onSummaryRow}">
<p:column colspan="3" style="text-align:right">
<h:outputText value="#{bundle.total}:" />
</p:column>
<p:column>
<!-- !!! NOTE THIS VALUE EXPRESSION !!! -->
<h:outputText value="#{component.parent.attributes.total}" />
</p:column>
</p:summaryRow>
</p:dataTable>
and this is the listener:
public void onSummaryRow(Object filter)
{
FacesContext facesContext = FacesContext.getCurrentInstance();
ELContext elContext = facesContext.getELContext();
ELResolver elResolver = elContext.getELResolver();
DataTable table = (DataTable) UIComponent.getCurrentComponent(facesContext);
UIColumn sortColumn = table.getSortColumn();
ValueExpression expression = sortColumn.getValueExpression("sortBy");
ValueReference reference = ValueExpressionAnalyzer.getReference(expression);
String property = (String) reference.getProperty();
int total = 0;
List<?> rowList = (List<?>) table.getValue();
for(Object row : rowList)
{
Object value = elResolver.getValue(elContext, row, property);
if(filter.equals(value))
{
// THIS IS THE ONLY POINT TO CUSTOMIZE
total += ((UnitResult) row).getCount();
}
}
List<UIComponent> children = table.getSummaryRow().getChildren();
UIComponent column = children.get(children.size() - 1);
column.getAttributes().put("total", total);
}
This listener has no external references: it does not depend on previous onSort events/listeners and it doesn't need any field in the bean.
I will suggest a possible way to do this, may not be the most perfect, but i believe it will help.
Ther's the steps:
1 - Declare a class atribute to acumulate the total group value:
...
#Named(value = "myBean")
#YourScope
public class InscricaoBean implements Serializable {
...
//in this example i will use a int type
private int acumulatorAux = 0;
...
2 - Create a function to return the total value per group:
...
public int getAcumulatedValue() {
int aux = acumulatorAux ;
acumulatorAux = 0;
return aux;
}
...
3 - Create an method to acumulate values per group:
...
public void acumulateValue(int value)
{
acumulatorAux += value;
}
...
4 - On JSF page, you need to call acumulateValue method for every row, something like:
...
<p:dataTable value="#{myBean.getList()}" var="testVar">
<p:column headerText="Header" sortBy="#{testVar.name}">
#{inscricaoBean.acumulateValue(testVar.value)}
<h:outputText value="#{testVar.name}" />
</p:column>
...
5 - And next, you can have a summaryRow like:
...
<p:summaryRow>
<p:column colspan="1" style="text-align:right">
<h:outputText value="Total:" />
</p:column>
<p:column>
<h:outputText value="#{inscricaoBean.getAcumulatedValue()}" />
</p:column>
</p:summaryRow>
...
Well, this is a gross way to acomplish this task. I think you can improve, but it was the first think when i see your question.
Hope it helps.
by using Lambda expression it works in java 1.7 with EL 3.0
n your JSF it would be like this :
<p:summaryRow>
<p:column colspan="3" style="text-align:right">
<h:outputText value="Total:" />
</p:column>
<p:column>
<h:outputText value="#{car.stream().map(item->item.price).sum()}">
<f:convertNumber type="currency" currencySymbol="$" />
</h:outputText>
</p:column>
</p:summaryRow>
One approach is to pass the datatable's sortBy="#{car.brand}" value within the p:summaryRow into a backing method that uses a stream to compute price subtotal.
<h:form>
<p:dataTable var="car" value="#{dtSummaryRowView.cars}" sortBy="#{car.brand}">
<p:column headerText="Id" sortBy="#{car.id}">
<h:outputText value="#{car.id}" />
</p:column>
<p:column headerText="Year" sortBy="#{car.year}">
<h:outputText value="#{car.year}" />
</p:column>
<p:column headerText="Brand" sortBy="#{car.brand}">
<h:outputText value="#{car.brand}" />
</p:column>
<p:column headerText="Color" sortBy="#{car.color}">
<h:outputText value="#{car.color}" />
</p:column>
<p:summaryRow>
<p:column colspan="3" style="text-align:right">
<h:outputText value="Total:" />
</p:column>
<p:column>
<h:outputText value="#{dtSummaryRowView.brandSubtotal(car.brand)}">
<f:convertNumber type="currency" currencySymbol="$" />
</h:outputText>
</p:column>
</p:summaryRow>
</p:dataTable>
</h:form>
.
public double brandSubtotal(String brand) {
return cars.stream().filter(c -> c.getBrand().equals(brand)).mapToDouble(c -> c.getPrice()).sum();
}
Another approach is to use the listener in p:summaryRow to set a backing bean attribute and then use getter to display the attribute.
<p:summaryRow listener="#{dtSummaryRowView.computeSubtotal(car.brand)}">
<p:column colspan="3" style="text-align:right">
<h:outputText value="Total:" />
</p:column>
<p:column>
<h:outputText value="#{dtSummaryRowView.subTotal}">
<f:convertNumber type="currency" currencySymbol="$" />
</h:outputText>
</p:column>
</p:summaryRow>
.
public void computeSubtotal(String brand) {
subTotal = cars.stream().filter(c -> c.getBrand().equals(brand)).mapToDouble(c -> c.getPrice()).sum();
}
public double getSubTotal () {
return subTotal ;
}

Primefaces dialog fields not filled after click in CommandLink

I am using Primefaces 3.5 with Weblogic 11. I have a page where a dialog to edit a 'profile' entity ('perfil' in Portuguese) which is called from two places. First from a commandButton to insert a new profile. The second from a dataTable to edit a specific profile. Below, I show the code:
Snippet of XHTML page
<p:fieldset legend="Pesquisa de Perfil">
<p:panelGrid columns="2">
<f:facet name="footer">
<p:commandButton id="btnPesquisar"
actionListener="#{perfilAcessoMB.pesquisar}" value="Pesquisar"
immediate="true" update="pnlPerfis" styleClass="ui-icon-search" />
<p:spacer width="20"></p:spacer>
<!-- OPEN DIALOG TO CREATE A NEW PROFILE -->
<p:commandButton id="btnIncluir" value="Incluir"
update="dlgPerfil" immediate="true"
actionListener="#{perfilAcessoMB.abrirDialogoEdicao(null)}"
oncomplete="dlgPerfil.show();">
</p:commandButton>
</f:facet>
</p:panelGrid>
</p:fieldset>
<br />
<p:outputPanel id="pnlPerfis" layout="block">
<p:fieldset id="resultadoPesquisa" legend="Resultado da Pesquisa"
rendered="#{not empty perfilAcessoMB.perfis}">
<p:dataTable id="tblPerfis" value="#{perfilAcessoMB.perfis}"
var="perfil" emptyMessage="Nenhum perfil encontrado.">
<p:column headerText="Nome do Perfil">
<h:outputText value="#{perfil.nome}"></h:outputText>
</p:column>
<p:column headerText="Descrição do Perfil">
<h:outputText value="#{perfil.descricao}"></h:outputText>
</p:column>
<p:column headerText="Situação do Perfil"
style="text-align: center; width: 100px;">
<h:outputText value="Ativo" rendered="#{perfil.situacao}" />
<h:outputText value="Inativo" rendered="#{not perfil.situacao}" />
</p:column>
<p:column headerText="Editar"
style="text-align: center; width: 50px;">
<!-- OPEN DIALOG TO EDIT A NEW PROFILE -->
<p:commandLink id="lnkEditar" immediate="true"
title="Editar Perfil" update=":formPrincipal:dlgPerfil :formPrincipal:pnlPerfilEdicao"
actionListener="#{perfilAcessoMB.abrirDialogoEdicao(perfil)}"
oncomplete="dlgPerfil.show();">
<h:outputText value="Editar" />
</p:commandLink>
</p:column>
<p:column headerText="Excluir"
style="text-align: center; width: 50px;">
</p:column>
</p:dataTable>
</p:fieldset>
</p:outputPanel>
<p:dialog id="dlgPerfil" widgetVar="dlgPerfil" resizable="false"
closable="true" modal="true" closeOnEscape="true"
header="#{(empty perfilAcessoMB.perfil)? 'Incluir': 'Editar'} Perfil">
<h:outputText value="#{perfilAcessoMB.perfil}"></h:outputText>
<h:panelGroup id="pnlPerfilEdicao" layout="block">
<p:fieldset legend="Dados do Perfil">
<p:panelGrid columns="2">
<h:outputLabel id="lblNomePerfilEdicao" value="Nome do Perfil"
for="txtNomePerfilEdicao" />
<p:inputText id="txtNomePerfilEdicao" required="true"
requiredMessage="É obrigatório preencher o campo Nome do Perfil."
value="#{perfilAcessoMB.perfil.nome}" maxlength="20" size="20"></p:inputText>
<h:outputLabel id="lblDescricaoPerfilEdicao"
value="Descrição do Perfil" for="txtDescricaoPerfilEdicao" />
<p:inputText id="txtDescricaoPerfilEdicao" required="true"
requiredMessage="É obrigatório preencher o campo Descrição do Perfil."
value="#{perfilAcessoMB.perfil.descricao}" maxlength="20"
size="20"></p:inputText>
<h:outputLabel id="lblSituacaoPerfilEdicao" value="Situação"
for="selSituacaoPerfilEdicao" />
<p:selectOneMenu id="selSituacaoPerfilEdicao"
value="#{perfilAcessoMB.perfil.situacao}">
<f:selectItems value="#{perfilAcessoMB.situacoesEdicao}" />
</p:selectOneMenu>
</p:panelGrid>
</p:fieldset>
<br />
<p:fieldset legend="Permissões">
<p:pickList id="pickFuncoes" value="#{perfilAcessoMB.funcoes}"
var="funcao" itemValue="#{funcao}"
itemLabel="#{funcao.descricao}" required="true"
requiredMessage="É obrigatório associar ao menos uma funcionalidade ao perfil."
converter="funcaoConverter" />
<p:column>#{funcao.descricao}</p:column>
</p:fieldset>
<p:panelGrid columns="2">
<p:commandButton id="btnSalvarPerfil" value="Salvar"
actionListener="#{perfilAcessoMB.salvar}"
oncomplete="if(args && !args.validationFailed) dlgPerfil.hide();" />
<p:commandButton id="btnCancelarPerfil" value="Cancelar"
immediate="true" onclick="dlgPerfil.hide();" />
</p:panelGrid>
</h:panelGroup>
</p:dialog>
MangedBean (perfilAcessoMB)
#ManagedBean
#ViewScoped
public class PerfilAcessoMB extends BaseMB {
private PerfilAcessoORM perfil;
private List<PerfilAcessoORM> perfis;
private String nomePerfil;
private Boolean situacao;
private DualListModel<FuncaoORM> funcoes;
private SelectItem[] situacoesPesquisa = new SelectItem[] {
new SelectItem(null, "Todos"), SELECT_ITEM_ATIVO,
SELECT_ITEM_INATIVO };
private SelectItem[] situacoesEdicao = new SelectItem[] {
SELECT_ITEM_ATIVO, SELECT_ITEM_INATIVO };
private FuncaoORM funcaoA = new FuncaoORM(1L, "FUNÇÃO A"), //
funcaoB = new FuncaoORM(2L, "B Function"), //
funcaoC = new FuncaoORM(10L, "Se Funssaum");
public void abrirDialogoEdicao(PerfilAcessoORM p) {
this.perfil = (p == null)? new PerfilAcessoORM(): p;
System.out.println("PerfilAcessoMB.onAbrirDialogoEdicao(): "
+ this.perfil);
List<FuncaoORM> funcoesDisponiveis = new ArrayList<FuncaoORM>(
Arrays.asList(funcaoA, funcaoB, funcaoC));
// Remove from funcoesDisponiveis those whose are present in perfil.
if (this.perfil.getFuncoes() == null) {
this.funcoes = new DualListModel<FuncaoORM>(funcoesDisponiveis,
Lists.<FuncaoORM> newArrayList());
} else {
funcoesDisponiveis.removeAll(this.perfil.getFuncoes());
this.funcoes = new DualListModel<FuncaoORM>(funcoesDisponiveis,
this.perfil.getFuncoes());
}
}
// Getters & Setters
}
PerfilAcessoORM (Profile) Entity
public class PerfilAcessoORM {
private Long id;
private String nome;
private String descricao;
private Boolean situacao = null;
private List<FuncaoORM> funcoes;
// Getters & Setters
}
FuncaoORM Entity:
public class FuncaoORM {
private Long id;
public String descricao;
// Getters & Setters
}
What is my problem? Apparently, when I want insert a new Profile, all seems OK. However, when I click to edit an existent profile to open the dialog, although the outputText and pickList are correctly filled, the inputText's and selectOneMenu are not.
Looking for solutions, I found here a suggestion to use appendToBody="true" in dialog. When I tried, the inputText's and selectOneMenu are correctly filled. However, the validation is not working as waited. When I click to save it is showed a message indicating that pickList is not filled, even if it is really filled. Actually, even if inputText's are not filled, there is no message about these inputTexts although they are required.
Another alternative would be use <f:setPropertyActionListener> inside commandLink:
<!-- OPEN DIALOG TO CREATE A NEW PROFILE -->
<p:commandButton id="btnIncluir" value="Incluir"
update="dlgPerfil" immediate="true"
actionListener="#{perfilAcessoMB.abrirDialogoEdicao}"
oncomplete="dlgPerfil.show();">
<f:setPropertyActionListener target="#{perfilAcessoMB.perfil}" value="#{null}"/>
</p:commandButton>
<!-- OPEN DIALOG TO EDIT A NEW PROFILE -->
<p:commandLink id="lnkEditar" immediate="true"
title="Editar Perfil" update=":formPrincipal:dlgPerfil :formPrincipal:pnlPerfilEdicao"
actionListener="#{perfilAcessoMB.abrirDialogoEdicao}"
oncomplete="dlgPerfil.show();">
<f:setPropertyActionListener target="#{perfilAcessoMB.perfil}" value="#{perfil}"/>
<h:outputText value="Editar" />
</p:commandLink>
The actionListener method would changed to:
public void abrirDialogoEdicao() {
if(this.perfil == null) {
this.perfil = new PerfilAcessoORM();
}
System.out.println("PerfilAcessoMB.onAbrirDialogoEdicao(): "
+ this.perfil);
// The rest remains the same ...
}
Now, when I click to create a new perfil, although in actionListener method the perfil attribute is filled, I got a NullPointerException when the dialog is renderized. It is like first is called perfilAcessoMB.setPerfil(), after the dialog is opened and finally actionListener method. On the other hand, if I click to edit an existent profile, I return to initial situation.
Therefore, I am lost, without idea how to solve this issue.
Thanks,
Rafael Afonso
The solution was incredible simple: just added process="#this" to both commandButtons.
<!-- OPEN DIALOG TO EDIT A NEW PROFILE -->
<p:commandLink id="lnkEditar" immediate="true"
title="#{msg['titulo.edicao']}" process="#this"
update=":formPrincipal:dlgPerfil"
actionListener="#{perfilAcessoMB.abrirDialogoEdicao(perfil)}"
oncomplete="dlgPerfil.show();">
<h:outputText value="#{msg['titulo.edicao']}" />
</p:commandLink>

primefaces treetable

i'm very new to primefaces. i create a treetable, all item get from database. my problem is if i select a child item, the actual selected is parent item, so then i cannot make operation on child item. here is my treetable code
<p:treeTable id="treeTable" value="#{aZoningController.root}" var="zonning" >
<p:column style="text-align: left; width: 93%">
<f:facet name="header">
#{lbl.aZoning_pokok}
</f:facet>
<h:outputText value="#{zonning.nama}" />
</p:column>
<p:column style="text-align: center; width: 5%">
<f:facet name="header">
#{lbl.aZoning_kod}
</f:facet>
<h:outputText value="#{zonning.kod}" />
</p:column>
<p:column style="vertical-align: text-top">
<p:menuButton value="" styleClass="mb">
<p:menuitem value="Update" oncomplete="confirmation.show()" process="#this" update=":actionForm:actionDialog" icon="ui-icon-document-b">
<f:setPropertyActionListener value="#{zonning}" target="#{aZoningController.selectedNode}" />
</p:menuitem>
<p:menuitem value="Delete" oncomplete="confirmation.show()" process="#this" update=":myform:confirmDialog" icon="ui-icon-trash">
<f:setPropertyActionListener value="#{zonning}" target="#{aZoningController.selectedNode}" />
</p:menuitem>
</p:menuButton>
</p:column>
</p:treeTable>
and i'm populate the tretable using this
public TreeNode getRoot() {
root = new DefaultTreeNode("Root", null);
List<aZoning> zon = ejbFacade.getRoot();
for (aZoning z : zon) {
TreeNode zonning = new DefaultTreeNode(z, root);
createNode(z.getId(), zonning);
}
return root;
}
private TreeNode createNode (String idParent, TreeNode parent) {
TreeNode node = null;
List<aZoning> zonning = ejbFacade.getZonning(idParent);
for (aZoning z : zonning) {
node = new DefaultTreeNode(z, parent);
createNode(z.getId(), node);
}
return node;
}
Please advice me
<f:setPropertyActionListener value="#{zonning}" target="#{aZoningController.selectedNode}" />
This sets the value of zonning to the selectedNode property of your aZoningController class. Instead of zonning, try setting the value that you need when the menuItem is selected. zonning is the value of the parent node, which is causing the issue.

Active Index of tabview not getting updated automatically

Active Index is not getting updated automatically. ReaD in a few posts that by placing the tabView on a form it works. Or by including <p:ajax event="tabChange"/> in the tabview it works. But nothing seems to work
xhtml
Sample 1 : automatic updates
<p:tabView id="categoryTabView" var="promoArticle" value="#{promotionDetailBean.artDTOs}" activeIndex="#{promotionDetailBean.activeTabIndex}">
<p:tab id="categoriesTab" title="#{promoArticle.categoryName}">
<p:dataTable id="promotionDetail_dataTable" var="articlePromo" value="#{promoArticle.artVO}" selection="#{promotionDetailBean.selectedArt}" rowIndexVar="rowIndex">
<p:column id="select" selectionMode="multiple" />
<p:column id="barCode">
<h:inputText id="barCodeInputTxt" value="#{articlePromo.barCode}"
styleClass="inputTextStyle" onchange="onSuggestedValueChange('categoryTabView',#{promotionDetailBean.activeTabIndex}, 'promotionDetail_dataTable',#{rowIndex},'originalCostInputTxt')" />
</p:column>
</p:dataTable>
</p:tab>
</p:tabView>
Sample 2: Updating on tabChange event
<h:form id="form">
<p:growl id="growlm" showDetail="true" />
<p:tabView id="categoryTabView" var="promoArticle" value="#{promotionDetailBean.artDTOs}" >
<p:ajax event="tabChange" listener="#{promotionDetailBean.tabChanged}" update=":growlm" />
<p:tab id="categoriesTab" title="#{promoArticle.categoryName}">
<p:dataTable id="promotionDetail_dataTable" var="articlePromo" value="#{promoArticle.artVO}" selection="#{promotionDetailBean.selectedArt}" rowIndexVar="rowIndex">
<p:column id="select" selectionMode="multiple" />
<p:column id="barCode">
<h:inputText id="barCodeInputTxt" value="#{articlePromo.barCode}"
styleClass="inputTextStyle" onchange="onSuggestedValueChange('categoryTabView',#{promotionDetailBean.activeTabIndex}, 'promotionDetail_dataTable',#{rowIndex},'originalCostInputTxt')" />
</p:column>
</p:dataTable>
</p:tab>
</p:tabView>
I need to identify the cell on "onChange " event. But the activeIndex is always 0, the initialized value. The event doesn't get call.
bean
private Integer activeTabIndex = 0;
public Integer getActiveTabIndex() {
return activeTabIndex;
}
public void setActiveTabIndex(Integer activeTabIndex) {
this.activeTabIndex = activeTabIndex;
}
bean
public void tabChanged(TabChangeEvent event){
TabView tv = (TabView) event.getComponent();
this.activeTabIndex = tv.getActiveIndex();
}
But the event is not getting trigerred. Nor getting updated automatically.
What could be the probable issues ?
Thanks,
Shikha
This works for me when the tab is not contained inside a form but every tab contains its own one:
Add a listener to tab change event to your tabView component:
<p:ajax event="tabChange" listener="#{userBean.onTabChange}" />
Getting the active index from the underlying TabView component doesn't seem to be working. However, in the event, the new selected tab is updated correctly so we can getthe index by searching in the children components of the TabView:
public void onTabChange(TabChangeEvent event)
{
TabView tabView = (TabView) event.getComponent();
activeTab = tabView.getChildren().indexOf(event.getTab());
}
I hope this works for you too
The following worked for me:
XHTML:
<p:tabView id="categoryTabView" var="promoArticle"
value="#{promotionDetailManagedBean.articuloPromocionDTOs}" dynamic="true">
<p:ajax event="tabChange" listener="#{promotionDetailManagedBean.onTabChange}" />
<p:tab> ... </p:tab>
</p:tabView>
Bean:
public final void onTabChange(final TabChangeEvent event) {
TabView tv = (TabView) event.getComponent();
this.activeTabIndex = tv.getActiveIndex();
}
For primefaces >= 5.0
please use the following code :
public final void onTabChange(TabChangeEvent event) {
TabView tv = (TabView) event.getComponent();
this.ActiveIndex = tv.getChildren().indexOf(event.getTab());
}
That only seems to work if active index is not binded to the managed bean. But this is useless for me since I want to keep a backing bean-view synchronization. I'm astonished Primefaces team has not resolved it yet (I'm working with 3.5 version). However it works if the p:tabView itself is wrapped into a h:form instead of having one of them for each tab, but this makes you change your submit context.
<p:column id="barCode">
<h:inputText id="barCodeInputTxt" value="#{articlePromo.barCode}"
styleClass="inputTextStyle" onchange="onSuggestedValueChange('categoryTabView',
#{promotionDetailBean.activeTabIndex},
'promotionDetail_dataTable',#{rowIndex},
'originalCostInputTxt')" /> **_____/>_____**
</p:column>
you have an extra />
immediate true may cause problem with p:ajax, you should use immediate true when you dont have validation or you are trying cancel operation.
public void tabChange(TabChangeEvent event){
TabView tabView = (TabView) event.getComponent();
Tab tab = (Tab) event.getTab();
String tabChangedMessage = tab.getTitle() + " changed. index=" + tabView.getActiveIndex();
System.out.println(tabChangedMessage);
FacesContext fc = FacesContext.getCurrentInstance();
fc.addMessage(null, new FacesMessage("Tab changed", tabChangedMessage));
}
<p:tabView>
<p:ajax event="tabChange" listener="#{tabChangeBean.tabChange}" update=":growlId" />
<p:tab title="tab 1">
tab1 inside
</p:tab>
<p:tab title="tab 2">
tab1 inside
</p:tab>
</p:tabView>
This works but active index is 0.
in your xhtml you are calling listener="#{promotionDetailBean.onTabChange}" but in your bean the method name is "public void tabChanged". So it cannot trigger.
I have tried an example on prime-showcase at:
in bean (TabBean):
private Integer activeTabIndex = 1;
// setter/getter
public void onTabChange(TabChangeEvent event) {
FacesMessage msg = new FacesMessage("Tab Changed", "Active Tab: " + event.getTab().getTitle());
TabView tabView = (TabView) event.getComponent();
int activeTabIndex = tabView.getActiveIndex();
System.out.println("--------" + activeTabIndex);
FacesContext context = FacesContext.getCurrentInstance();
Map<String, String> params = context.getExternalContext().getRequestParameterMap();
String activeIndexValue = params.get(tabView.getClientId(context) + "_activeIndex");
System.out.println("--------" + activeIndexValue);
context.addMessage(null, msg);
}
in xhtml (tabviewChangeListener.xhtml):
<p:tabView id="tabView" dynamic="true" activeIndex="#{tabBean.activeTabIndex}">
<p:ajax event="tabChange" listener="#{tabBean.onTabChange}" update=":form:growl"/>
<p:tab title="Godfather Part I" id="Godfather1">
The result is as expected:
At beginning the second tab is displayed. I click first tab and then third. sysout is:
--------0
--------0
--------2
--------2
i easy fix this with:
public void onSPTabChange(TabChangeEvent event)
{
TabView tabView = (TabView) event.getComponent();
currentData.setSP_Index(tabView.getChildren().indexOf(event.getTab())+1);
}
in currentdata i have property SP_Index with number of tab (first,second....)
<p:tabView id="tabView" styleClass="tabView">
<p:ajax event="tabChange" listener="#{dataAccess.onSPTabChange}" />
....
and add jquery script
<script>
$("#tabView li:nth-child(#{currentData.SP_Index})").click();
</script>
public final void onTabChange(final TabChangeEvent event) {
TabView tv = (TabView) event.getComponent();
this.activeTabIndex = tv.getIndex();
}
This worked for me...