the situation is the following: I've got a treeTable with 3 different type of objects. The table contains the p:ajax with event="select". I wrote 3 different contextMenus, one for each type... and all works well.
My problem is that I want to enable/disable some of the menuItems; to do that I use the attribute "rendered" with condition based on properties of selected node.
All works, but only the second time I right-click on the same object (the first time the contextMenu isn't filtered).
Here is the code... (I'm including only one type of object for semplicity)
treeTable page:
<h:form id="form" prependId="false">
<p:treeTable value="#{documentsController.root}" var="document" id="docs"
selectionMode="single" selection="#{documentsController.selectedNode}">
<p:ajax event="select" process="#this" update=":form:menus"/>
<p:column headerText="#{msg['name']}">
<h:outputText value="#{document.name}" />
</p:column>
</p:treeTable>
<h:panelGroup id="menus">
<ui:include src="/menu/document_menu.xhtml"/>
</h:panelGroup>
<p:dialog id="document-rename-dialog" widgetVar="documentRenameDialog" header="#{msg.rename}">
<h:panelGrid id="doc-rename" columns="2">
<h:outputLabel for="name" value="#{msg.name}:" />
<h:inputText id="name" value="#{documentsController.name}"/>
</h:panelGrid>
<div class="spacer-10" />
<h:panelGroup layout="block">
<p:commandLink onclick="documentRenameDialog.hide();" value="#{msg.cancel}"/>
<p:commandLink actionListener="#{documentsController.renameDocument(documentsController.selectedNode.data)}"
process="#this :form:document-rename-dialog:doc-rename"
update=":form:docs"
oncomplete="documentRenameDialog.hide();"
value="#{msg.check}">
</h:panelGroup>
</common:dialog>
</h:form>
document_menu page:
<p:contextMenu id="contextMenuDocument" for="docs" nodeType="document">
<p:menuitem value="#{msg.rename}" process="#this docs" update=":form:document-rename-dialog:doc-rename"
actionListener="#{documentsController.setName(documentsController.selectedNode.data.name)}"
rendered="#{documentsController.canWrite}"
icon="ui-icon-pencil" oncomplete="documentRenameDialog.show();"/>
</p:contextMenu>
DocumentsController class:
#ManagedBean
#ViewScoped
public class DocumentsController {
private TreeNode root;
private TreeNode selectedNode;
private String name;
public TreeNode getSelectedNode() {
return selectedNode;
}
public void setSelectedNode(TreeNode selectedNode) {
this.selectedNode = selectedNode;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void renameDocument(ArterDocument selectedDocument) {
if(name != null && !name.equals("")) {
System.out.println("Document renamed in: "+name);
((MyDocument)selectedNode.getData()).setName(name);
}
else
addErrorMessage("Error renaming document.");
}
public static boolean canWrite() {
if(((MyDocument)selectedNode.getData()).isWriteable())
return true;
return false;
}
}
The MyDocument class is a simple class with a String (name) and a boolean (writeable).
Can anyone tell me how I can show filtered contextMenu at first shot?
Thank you!
Related
I am trying to pass an object from populated with items table to Controller. Then I use JS alert to verify success. However I fail to pass anything from the table.
Any help would be appreciated.
issues.xhtml
<p:dataTable var="issue" value="#{issuesController.findWithParameter(issues, startenddates)}" styleClass="list" selectionMode="single" selection="#{issuesController.issue}" rowKey="#{issue.id}" >
<p:ajax event="rowSelect" update="mainForm" listener ="#{issuesController.onRowSelect}"
oncomplete="alert(args.name)"/>
<p:column headerText="Id" id = "head_id" style="width:0%; padding: 0px;">
<h:outputText value="#{issue.id}"/>
</p:column>
<p:column headerText="Child" id = "head_child" style="width:12%;">
<h:outputText value="#{issue.child}"/>
</p:column>
...
</p:dataTable>
IssuesController.java
#Named("issuesController")
#RequestScoped
public class IssuesController implements Serializable {
#Inject
private Issues issue;
....
public void onRowSelect(SelectEvent event) throws IOException {
Issues i = (Issues) event.getObject();
String toWrite;
if (i == null) {
toWrite = "Item is not recieved";
} else {
toWrite = i.toString();
}
RequestContext.getCurrentInstance().addCallbackParam("name", toWrite);
}
Issues.java
#Named("issues")
#SessionScoped
#XmlRootElement
public class Issues implements Serializable {
....
}
I tried different types of scope, tried f:attribute...neither of this worked...
Try using process="#this" and change the scope to
#ViewScoped.
I'm pretty new to Primefaces and I'm having trouble understanding how it works. I'm trying to create a datatable that will show a series of records that are grouped according to one of the fields (area), with a header row indicating the area of the rows beneath it. There is a tag in Primefaces (since 6.0.11), "p:headerRow", but it's unavailable for my version, Primefaces 5.3. There is also an attribute in the "column" tag, "groupRow", but it's unavailable for my version as well. One idea that comes to mind is to use a conditional header row that will show the value of area for the following rows, depending on whether the area has changed (if not, do not show the header; if yes, show it). I wanted to use a variable "areaActual" to keep track of the area being rendered, to be compared with the area of the next row in the table. I hope I'm being clear... But the variable does not seem to work, and the header row does not show up as a header (if I remove the "rendered" condition). Please help!
This is the xhtml.:
<h:panelGroup id="pgbody" styleClass="backBeanChangeBody" rendered="#{informacionpersonal$kardex.existe}">
<p:dataTable id="dataTablePrincipal"
style="height:100%;width:100%" value="#{informacionpersonal$kardex.listaKardex}" var="currentRow" rows="10"
paginator="true" rowsPerPageTemplate="10,15,20,25,30" reflow="true" >
<p: rendered="#{!currentRow.area eq areaActual}">
<p:column id="encabezado" colspan="7">
<p:outputLabel value="#{areaActual}" />
</p:column>
</p:row>
<ui:param name="areaActual" value="#{currentRow.area}" />
<p:row>
<p:column id="column3" sortBy="#{currentRow.espAsignatura}">
<p:outputLabel id="outputText5" value="#{currentRow.espAsignatura}"/>
<f:facet name="header">
<p:outputLabel value="Asignatura"/>
</f:facet>
</p:column>
<p:column id="column5" sortBy="#{currentRow.espPeriodoescolar}">
<p:outputLabel value="#{currentRow.espPeriodoescolar}" />
<f:facet name="header">
<p:outputLabel value="Periodo escolar"/>
</f:facet>
</p:column>
<p:column id="column6" sortBy="#{currentRow.creditos}">
<p:outputLabel value="#{currentRow.creditos}" />
<f:facet name="header">
<p:outputLabel value="Créditos"/>
</f:facet>
</p:column>
<p:column id="column7" sortBy="#{currentRow.espTipoevaluacion}">
<p:outputLabel value="#{currentRow.espTipoevaluacion}" />
<f:facet name="header">
<p:outputLabel value="Tipo de evaluación"/>
</f:facet>
</p:column>
<p:column id="column12" sortBy="#{currentRow.calificacion}">
<p:outputLabel value="#{currentRow.calificacion}"/>
<f:facet name="header">
<p:outputLabel value="Calificación"/>
</f:facet>
</p:column>
</p:row>
</p:dataTable>
</h:panelGroup>
This is the bean:
#ManagedBean(name = "informacionpersonal$kardex")
#ViewScoped
public class kardex extends FacesBean implements Serializable {
private int __placeholder;
private void _init() throws Exception {
selectOneMenu1DefaultItems.setItems(new String[]{"10", "15", "20", "25", "30"});
}
private FormaModal formaModal = (FormaModal) getValue("#{plantilla.formaModal}");
private Boolean notselectedrow = true;
private DefaultSelectionItems selectOneMenu1DefaultItems = new DefaultSelectionItems();
public DefaultSelectionItems getSelectOneMenu1DefaultItems() {
return selectOneMenu1DefaultItems;
}
public void setSelectOneMenu1DefaultItems(DefaultSelectionItems dsi) {
this.selectOneMenu1DefaultItems = dsi;
}
public Boolean getNotselectedrow() {
return notselectedrow;
}
public void setNotselectedrow(Boolean notselectedrow) {
this.notselectedrow = notselectedrow;
}
private TableListDataModel tabla;
public TableListDataModel getTabla() {
return tabla;
}
public void setTabla(TableListDataModel tabla) {
this.tabla = tabla;
}
// </editor-fold>
private Persona alumno;
private Boolean existe;
private List<VEscHistoriaacademica> listaKardex;
public kardex() {
}
#PostConstruct
public void init() {
try {
_init();
} catch (Exception e) {
log("Page1 Initialization Failure", e);
throw e instanceof FacesException ? (FacesException) e : new FacesException(e);
}
listaKardex = new ArrayList<VEscHistoriaacademica>();
}
#PreDestroy
public void destroy() {
}
protected ApplicationBean1 getApplicationBean1() {
return (ApplicationBean1) getBean("ApplicationBean1");
}
protected Controlador getControlador() {
return (Controlador) getBean("Controlador");
}
public Persona getAlumno() {
return alumno;
}
public void setAlumno(Persona alumno) {
this.alumno = alumno;
listaKardex = new ArrayList<VEscHistoriaacademica>();
listaKardex.clear();
listaKardex = getControlador().findByAlumno(alumno.getId());
existe = !listaKardex.isEmpty();
}
public List<VEscHistoriaacademica> getListaKardex() {
return listaKardex;
}
public void setListaKardex(List<VEscHistoriaacademica> listaKardex) {
this.listaKardex= listaKardex;
}
public Boolean getExiste() {
return existe;
}
public void setExiste(Boolean existe) {
this.existe = existe;
}
}
Thank you!
I have a page (page1.xhtml) with a tabView and a dataTable within one of the tabs. The dataTableuses lazy loading and should provide multisort mode.
Therefore I use a List<SortMeta> for the sortBy attribute of dataTable as found here (Initial sortorder for PrimeFaces datatable with multisort).
The List<SortMeta> is created in getPreSortOrder() but findComponent() for clientId "myForm:tabs:data:colName" always returns null!
In another constellation (page2.xhtml) where I have the dataTable not in a tabView findComponent() always returns the correct column component!
So the problem seems to be the combination with tabView?!
Any hints welcome - Thank you!
page.xhtml:
<html>
<f:metadata>
<f:viewAction action="#{model.loadData}"/>
</f:metadata>
<ui:composition template="/WEB-INF/template.xhtml">
<ui:define name="content">
<h:form id="myForm">
<p:panelGrid>...</p:panelGrid>
<p:tabView id="tabs">
<p:tab id="tab1">...</p:tab>
<p:tab id="tab2">...</p:tab>
<p:tab id="tab3">
<p:dataTable id="data" lazy="true"
value="#{model.personTableModel}" var="item"
sortMode="multiple" sortBy="#{model.tableMode.preSortOrder}">
<p:column id="colName" sortBy="#{item.name}"> // <-- findComponent for "myForm:tabs:data:colName" always returns null !!!
<h:outputText value="#{item.name}"/>
</p:column>
<p:column id="colAddress" sortBy="#{item.address}">
<h:outputText value="#{item.address}"/>
</p:column>
</p:dataTable>
</p:tab>
</p:tabView>
</h:form>
</ui:define>
</ui:composition>
</html>
page2.xhtml:
<html>
<f:metadata>
<f:viewAction action="#{model.loadData}"/>
</f:metadata>
<ui:composition template="/WEB-INF/template.xhtml">
<ui:define name="content">
<h:form id="myForm">
<p:panelGrid>...</p:panelGrid>
<p:outputPanel id="tables">
<p:fieldset>
<p:dataTable id="data" lazy="true"
value="#{model.personTableModel}" var="item"
sortMode="multiple" sortBy="#{model.tableMode.preSortOrder}">
<p:column id="colName" sortBy="#{item.name}"> // <-- findComponent for "myForm:data:colName" always component
<h:outputText value="#{item.name}"/>
</p:column>
<p:column id="colAddress" sortBy="#{item.address}">
<h:outputText value="#{item.address}"/>
</p:column>
</p:dataTable>
<p:fieldset>
</p:outputPanel>
</h:form>
</ui:define>
</ui:composition>
</html>
Model.java:
#Named // javax.inject.Named
#ViewScoped // javax.faces.view.ViewScoped
public class Model implements Serializable {
private static final String COL_NAME_CLIENT_ID = "myForm:tabs:data:colName";
#Inject PersonTableDataModel personTableDataModel; // with getter & setter
public void loadData() {
List<SortMeta> preSortOrder = getPreSortOrder(COL_NAME_CLIENT_ID, "name", SortOrder.ASCENDING);
personTableDataModel.setPreSortOrder(preSortOrder);
}
private List<SortMeta> getPreSortOrder(String columnId, String sortField, SortOrder sortOrder) {
UIViewRoot viewRoot = FacesContext.getCurrentInstance().getViewRoot();
UIComponent column = viewRoot.findComponent(columnId); // <-- ALWAYS RETURNS NULL
if (Objects.isNull(column)) {
return Collections.emptyList();
}
List<SortMeta> preSortOrder = new ArrayList<>();
SortMeta sm = new SortMeta();
sm.setSortBy((UIColumn) column);
sm.setSortField(sortField);
sm.setSortOrder(sortOrder);
preSortOrder.add(sm);
return preSortOrder;
}
}
PersonTableDataModel.java:
public class PersonTableDataModel extends TableModel<Person> {
}
TableModel.java:
public class TableModel<T> extends LazyDataModel<T> {
private List<SortMeta> preSortOrder; // with getter & setter
}
I am using Primefaces 6.1 on Wildfly 10.0.0.Final
EDIT:
I added a TabChange event listener changeTab() and traversed the UIComponents and at the end the correct clientId is written to the output?!
Model.java:
public void changeTab(TabChangeEvent event) {
TabView tabView = (TabView) event.getComponent();
logger.entry(tabView.getActiveIndex());
Tab tabProzesse = tabView.findTab("myForm:tabs:tab3");
if (Objects.nonNull(tabProzesse)) {
List<UIComponent> childs = tabProzesse.getChildren();
Optional<UIComponent> c = childs.stream().filter(child -> child.getClientId().equals("myForm:tabs:data")).findFirst();
if (c.isPresent() && c.get() instanceof DataTable) {
DataTable t = (DataTable) c.get();
Optional<UIColumn> optColName = t.getColumns().stream().filter(col -> col.getClientId().contains("colName")).findFirst();
optColName.ifPresent(colName -> {
logger.debugf("colName.clientId=%s", colName.getClientId()); // <-- output colName.clientId=myForm:tabs:data:colName
});
}
}
}
I fixed it by this work-around:
added tabChange event listener to tabView and update datatable data
added binding to initial sort column with id colName
set preSortOrder for tableModel in onTabChange listener
page.xhtml:
<p:tabView id="tabs">
<p:ajax event="tabChange" listener="#{model.onTabChange}" update="data"/>
<p:tab id="tab1">...</p:tab>
<p:tab id="tab2">...</p:tab>
<p:tab id="tab3">
<p:dataTable id="data" lazy="true"
value="#{model.personTableModel}" var="item"
sortMode="multiple"
sortBy="#{model.personTableModel.preSortOrder}">
<p:column id="colName" sortBy="#{item.name}" binding="#{mode.colName}">
</p:column>
</p:dataTable>
</p:tab>
</p:tabView>
Model.java:
private UIComponent colName;
public UIComponent getColName() {
return colName;
}
public void setColName(UIComponent colNameProzess) {
this.colName = colName;
}
public void onTabChange(TabChangeEvent event) {
TabView tabView = (TabView) event.getComponent();
UIComponent uiComponent = findComponent(tabView, colName.getId());
if (Objects.nonNull(uiComponent) && uiComponent instanceof org.primefaces.component.api.UIColumn) {
List<SortMeta> preSortOrder = getPreSortOrder(uiComponent, "name", SortOrder.ASCENDING);
personTableDataModel.setPreSortOrder(preSortOrder);
}
}
private List<SortMeta> getPreSortOrder(UIColumn column, String sortField, SortOrder sortOrder) {
List<SortMeta> preSortOrder = new ArrayList<>();
SortMeta sm = new SortMeta();
sm.setSortBy(column);
sm.setSortField(sortField);
sm.setSortOrder(sortOrder);
preSortOrder.add(sm);
return preSortOrder;
}
private UIComponent findComponent(UIComponent uiComponent, String id) {
FacesContext context = FacesContext.getCurrentInstance();
UIComponent base = Objects.nonNull(uiComponent) ? uiComponent : context.getViewRoot();
final UIComponent[] found = new UIComponent[1];
base.visitTree(VisitContext.createVisitContext(context), (context1, component) -> {
if (component.getId().equals(id)) {
found[0] = component;
return VisitResult.COMPLETE;
}
return VisitResult.ACCEPT;
});
return found[0];
}
In the following example, I modify a datatable using p:ajax then use remoteCommand to update the table. That works. However, I would also like to update growl msgs in the event of an error or success. That doesn't work.
I see from the examples if a button calls an action, then calls remoteCommand, the growl msgs update. However, that won't give me what I need from the ajax cellEdit in a datatable.
How can I update the growl messages from a p:ajax command.
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui"
>
<h:head/>
<h:form id="formId">
<p:growl id="msgs" showDetail="true" />
<h:body>
<h:panelGrid>
<!-- Updates wordsId table but not msgs -->
<p:remoteCommand name="onCellEditRemote" update="wordsId msgs"/>
<p:dataTable id="wordsId" var="word" value="#{remoteMessageBean.words}" editable="true" editMode="cell">
<!-- does not update msgs -->
<p:ajax event="cellEdit" listener="#{remoteMessageBean.modifyWordOnCellEdit}" oncomplete="onCellEditRemote()" update="formId:msgs"/>
<p:column headerText="Modify" >
<p:outputLabel value="#{word}" />
</p:column>
<p:column headerText="Modify" >
<p:cellEditor>
<f:facet name="output"><h:outputText value=""/></f:facet>
<f:facet name="input">
<p:inputText id="modelInput" value="#{remoteMessageBean.modifyWord}"/>
</f:facet>
</p:cellEditor>
</p:column>
</p:dataTable>
</h:panelGrid>
<p:remoteCommand name="rc" update="msgs" />
<p:commandButton type="button" action="#{remoteMessageBean.buttonAction}" value="Doesnt Work" icon="ui-icon-refresh" update="msgs" />
<p:remoteCommand name="rc2" update="msgs" action="#{remoteMessageBean.buttonAction}" />
<p:commandButton type="button" onclick="rc2()" value="Works" icon="ui-icon-refresh" />
</h:body>
</h:form>
</html>
#ManagedBean
#SessionScoped
public class RemoteMessageBean {
private static Logger logger = Logger.getLogger(RemoteMessageBean.class);
private String modifyWord;
private List<String> words;
public RemoteMessageBean() {
words = new ArrayList<>();
words.add("word1");
words.add("word2");
words.add("word3");
}
public void modifyWordOnCellEdit(CellEditEvent event) {
logger.debug(event);
getWords().add(getModifyWord());
logger.debug("");
FacesMessage msg = new FacesMessage(FacesMessage.SEVERITY_ERROR, "adding " + getModifyWord(), null);
FacesContext.getCurrentInstance().addMessage(null, msg);
setModifyWord(null);
}
public void buttonAction() {
logger.debug("");
FacesMessage msg = new FacesMessage(FacesMessage.SEVERITY_ERROR, "buttonAction", null);
FacesContext.getCurrentInstance().addMessage(null, msg);
}
public String getModifyWord() {
return modifyWord;
}
public void setModifyWord(String modifyWord) {
this.modifyWord = modifyWord;
}
public List<String> getWords() {
return words;
}
}
I worked around the problem by creating and saving message in modifyWordOnCellEdit then calling displayMessageAction from remoteCommand to display it. Not exactly what I was hoping for but it works.
Jsf Page
<p:remoteCommand name="onCellEditRemote" update="wordsId" action="#{gameBean.displayMessageAction}"/>
Controller
public void displayMessageAction() {
if (getMessage() != null) {
FacesContext.getCurrentInstance().addMessage("growl", getMessage());
setMessage(null);
}
}
public void modifyWordOnCellEdit(CellEditEvent event) {
...
FacesMessage msg = new FacesMessage(FacesMessage.SEVERITY_ERROR, exception.getMessage(), null);
setMessage(msg);
}
Its will work add partialsubmit in p:ajax
after deleting one row in my dataTable I still have to refresh browser manually to see changes..can you advice me how to properly udpate my dataTable after deleting data pls?
<h:body>
<h:form id="form">
<p:growl id="msgs" showDetail="true" />
<p:dataTable id="items" var="items" value="#{itemView.items}"
editable="true" editMode="cell" widgetVar="cellItems">
<f:facet name="header">
Cell Editing with Click and RightClick
</f:facet>
<p:ajax event="cellEdit" listener="#{itemView.onCellEdit}"
update=":form:msgs" />
<p:column headerText="Name">
<p:cellEditor>
<f:facet name="output">
<h:outputText value="#{items.name}" />
</f:facet>
<f:facet name="input">
<p:inputText value="#{items.name}" style="width:96%" label="Name" />
</f:facet>
</p:cellEditor>
</p:column>
...next columns
<p:column headerText="Options" style="width:32px">
<p:commandLink id="deleteLink" styleClass="ui-icon ui-icon-trash" action="#{itemView.deleteItem(items.itemId)}" update=":form:items" ajax="true">
<p:confirm header="Confirmation" message="Are you sure?" icon="ui-icon-alert" />
</p:commandLink>
<p:confirmDialog global="true" showEffect="fade" hideEffect="explode">
<p:commandButton value="Yes" type="button" styleClass="ui-confirmdialog-yes" icon="ui-icon-check" />
<p:commandButton value="No" type="button" styleClass="ui-confirmdialog-no" icon="ui-icon-close" />
</p:confirmDialog>
</p:column>
</p:dataTable>
<p:growl id="growl" life="2000" />
<p:commandButton value="Add Item" id="ajax" update="msgs items" actionListener="#{itemView.buttonAction}" styleClass="ui-priority-primary" />
</h:form>
and this is my controller
public class ItemView implements Serializable {
private List<Item> items;
#ManagedProperty("#{itemService}")
private ItemService serviceItem;
#PostConstruct
public void init() {
items = serviceItem.getAllItems();
}
public List<Item> getItems(){
return items;
}
public List<String> getUseOrNotCriticalCount(){
return serviceItem.getUseOrNotCriticalCount();
}
public void setServiceItem(ItemService serviceItem){
this.serviceItem = serviceItem;
}
public void onRowEdit(RowEditEvent event) {
FacesMessage msg = new FacesMessage("Item Edited");
FacesContext.getCurrentInstance().addMessage(null, msg);
}
public void onRowCancel(RowEditEvent event) {
FacesMessage msg = new FacesMessage("Edit Cancelled");
FacesContext.getCurrentInstance().addMessage(null, msg);
}
public void onCellEdit(CellEditEvent event) {
Object oldValue = event.getOldValue();
Object newValue = event.getNewValue();
if(newValue != null && !newValue.equals(oldValue)) {
DataTable dataTable = (DataTable) event.getSource();
Item editedItem = (Item) dataTable.getRowData();
serviceItem.edit(editedItem);
System.out.println(editedItem.getName().toString());
FacesMessage msg = new FacesMessage(FacesMessage.SEVERITY_INFO, "Cell Changed", "Old: " + oldValue + ", New:" + newValue);
FacesContext.getCurrentInstance().addMessage(null, msg);
}
}
public void buttonAction(ActionEvent actionEvent) {
Item item = new Item("Nazov", 0,0,0,false,0,0,0);
serviceItem.add(item);
addMessage("New item has been added!");
}
public void addMessage(String summary) {
FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_INFO, summary, null);
FacesContext.getCurrentInstance().addMessage(null, message);
}
public void deleteItem(int itemId){
serviceItem.delete(itemId);
addMessage("Selected item has been deleted!");
}
}
It looks like you're updating correctly on the page, but you need to update on the bean too. So in deleteItem(int itemId) either remove the deleted item from the list of items manually, or call init() for refreshing.