Context
I have a datatable with a button that opens a dialog when clicked. That dialog shows additional data (xml content) in a p:inputTextarea
Question
Now I would like to make this p:inputTextarea editable and have the changes reflected in the object of the datatable. I wanted to add a commandbutton in the dialog to save the changes. How do I get a reference to the selected object ?
Xhtml
<h:form id="alltxform">
<p:dataTable id="tablealltx" var="transaction" value="#{transactionListModel.txList}">
<p:column>
<p:commandButton update=":alltxform:xmlDetail" oncomplete="PF('dialog').show()">
<f:setPropertyActionListener value="#{transaction}"
target="#{transactionListModel.selectedTx}" />
</p:commandButton>
</p:column>
</p:dataTable>
<p:dialog header="Detail" widgetVar="dialog">
<p:outputPanel id="xmlDetail">
<p:inputTextarea readonly="false" id="xmlviewer"
value="#{transactionListModel.selectedTx.xml}" />
</p:outputPanel>
</p:dialog>
</h:form>
Model
package model;
#Named
#SessionScoped
public class TransactionListModel implements Serializable {
private static final long serialVersionUID = 1L;
private List<TransactionVO> txList;
private TransactionVO selectedTx;
public TransactionVO getSelectedTx() {
return selectedTx;
}
public void setSelectedTx(TransactionVO selectedTx) {
this.selectedTx = selectedTx;
}
#PostConstruct
public void init() {
txList = new ArrayList<TransactionVO>();
}
public List<TransactionVO> getTxList() {
return txList;
}
public void clearList(){
txList = new ArrayList<TransactionVO>();
}
}
Button
I want to add this button to the dialog.
<p:commandButton value="OK" onclick="PF('dialog').hide();" actionListener=""/>
I read about cellEdit events, but that's not really what I need. I need a reference to my transaction object inside the dialog in order to save the changes.
Do you mean the dialog will look like -
<p:dialog header="Detail" widgetVar="dialog">
<p:outputPanel id="xmlDetail">
<p:inputTextarea readonly="false" id="xmlviewer"
value="#{transactionListModel.selectedTx.xml}" />
<p:commandButton value="OK" onclick="PF('dialog').hide();" actionListener=""/>
</p:outputPanel>
</p:dialog>
And the action will refresh the model, before refreshing the table?
And you want to access TransactionListModel.selectedTx?
Well if its in the model and accessible from the controller then just -
actionListener="#{yourController.yourAction(transactionListModel.selectedTx)}"
And Update the underlying datastructure in the yourAction method, before updating :tablealltx:tablealltx
I am using primefaces 5.1 and still facing problem with p:dialog and p:inputText within that dialog.
Here is the .xhtml content
<ui:define name="content">
<f:metadata> <f:viewAction action="#{vLoginController.initSetup}" /> </f:metadata>
<h:form id="vhome" prependId="false">
<table>
<tr>
<td>
<p:commandButton value="Place Order" action="#{vLoginController.placeOrderHomePage}"
update="logindialog, signupdialog"/>
</td>
</tr>
</table>
<p:dialog id="logindialog" header="Login / Sign up" visible="#{vLoginController.loginDialog}"
draggable="false" resizable="false" modal="true">
<p:messages autoUpdate="true"/>
<h:panelGrid columns="2" cellpadding="5">
<h:outputLabel for="inuserid" value="EmailID:" />
<p:inputText id="inuserid" size="40" value="#{vLoginController.user.userId}" />
<h:outputLabel for="inpassword" value="Password:" />
<p:password id="inpassword" size="20" value="#{vLoginController.user.password}" />
<f:facet name="footer">
<p:commandButton value="Login" process="#form" action="#{vLoginController.validateLogin}" update="logindialog"/>
<p:commandButton value="Sign up" action="#{vLoginController.showSignup}" update="logindialog, signupdialog"/>
</f:facet>
</h:panelGrid>
</p:dialog>
<p:dialog id="signupdialog" header="Sign up / Login" visible="#{vLoginController.signupDialog}"
draggable="false" resizable="false" modal="true">
<p:outputLabel>Test</p:outputLabel>
</p:dialog>
</h:form>
</ui:define>
Here is the supporting Bean
#Named
#SessionScoped
public class VLoginController extends BaseController implements Serializable {
private VUser user;
public VLoginController() {
}
public void placeOrderHomePage() {
loginDialog = true;
signupDialog = false;
}
public String validateLogin() {
// Validate the screen fields
FacesMessage msg = new FacesMessage();
msg.setSeverity(FacesMessage.SEVERITY_ERROR);
FacesContext context = FacesContext.getCurrentInstance();
if (user.getUserId() == null || user.getPassword() == null) {
msg.setSummary("Enter User ID and Password");
context.addMessage("screenvalidation", msg);
return null;
}
}
}
public class VUser implements Serializable {
public VUser() {
}
private int userSeq;
private String userId;
private String userType;
private String password;
private String salt;
private int active;
}
The userID and password in the user object are always null. Have gone through various forums content and tried like adding outputpanel around them etc., but none works. Have kept the code very similar to what the primefaces showcase says, still doesn't work.
Any solution please.. Please note that there is no problem in showing or hiding the dialog boxes, those logic works perfect. I just need to get the values entered by the user in the dialog fields to the bean..
In my application I am using ViewScoped Bean and it does not show selected row when a row is selected in primefaces datatable. But if I changed the Bean to a SessionScoped Bean then it shows the selected row perfectly.
my code is like below.
<h:form id="form">
<p:growl id="msgs" showDetail="true" />
<p:dataTable var="pMData" rowIndexVar="rowIndex" value="# {managedBean.dataModel}" selectionMode="single" paginator="true" rows="100"
widgetVar="pMTable" emptyMessage="No Records Found." filteredValue="#{managedBean.filteredRecords}" selection="#{managedBean.selectedRecord}" rowKey="#{pMData.cellid}">
<p:ajax event="rowSelect" listener="#{managedBean.onRowSelect}"
update=":form:display :form:msgs" oncomplete="moreviewDialog.show()" />
<p:ajax event="rowUnselect" listener="#{managedBean.onRowUnselect}" update=":form:msgs"/>
<p:column headerText="Cell Name" filterBy="#{pMData.cellid}" filterStyle="display:none" >
<h:outputText value="#{pMData.modifiedCellID}" />
</p:column>
</p:dataTable>
<p:dialog header="History Data" widgetVar="moreviewDialog" resizable="false" id="moreviewDlg"
showEffect="fade" hideEffect="explode" modal="true">
<h:panelGrid id="display" columns="2" cellpadding="4" style="margin:0 auto;">
<p:lineChart id="category" value="# {managedBean.createCategoryModel(managedBean.selectedRecord.cellid)}" legendPosition="e"
title="NodeB Throughput(kbit/s)" minY="0" maxY="5000" style="height:300px;margin-top:20px"/>
</h:panelGrid>
</p:dialog>
</h:form>
and my managedBean CDI is like this.
#Named(value = "managedBean")
#ViewScoped
public class ManagedBean implements Serializable {
public void setSelectedRecord(PMData selectedRecord1){
this.selectedRecord=selectedRecord1;
}
public PMData getSelectedRecord(){
return selectedRecord;
}
public void onRowSelect(SelectEvent event) {
FacesMessage msg = new FacesMessage("NodeB Selected", String.valueOf(((PMData) event.getObject()).getCellid()));
FacesContext.getCurrentInstance().addMessage(null, msg);
}
public void onRowUnselect(UnselectEvent event) {
FacesMessage msg = new FacesMessage("Row Unselected",((PMData) event.getObject()).getCellid());
FacesContext.getCurrentInstance().addMessage(null, msg);
}
public PMDataModel getDataModel() {
return dataModel;
}
public CartesianChartModel createCategoryModel(String key) { .....}
public List<PMData> getFilteredRecords() {
return filteredRecords;
}
public void setFilteredRecords(List<PMData> filteredRecords) {
// System.out.println("came ");
this.filteredRecords = filteredRecords;
}
}
and PMData and PMDataModel classes are working normally. Can someone help me to select the row while still using viewscoped bean.
I think I found the answer. the error is with the dialogbox. I put dynamic=true in dialogbox. Now working perfectly.
I know this is a very common issue which happens for a variety of reasons, but although I have searched about it a lot, I didn't manage to find a solution for my case.
My primefaces commandButton is inside an h:form and is declared as follows:
<p:commandButton action="#{userGroupBean.createOrUpdateItemAction}"
value="#{userGroupBean.actionCreateOrUpdateLabel}"
icon="iconDisk"
update="#form"
oncomplete="window.scrollTo(0,0);" />
My UserGroupBean is ViewScoped.
This button when clicked is supposed to create a userGroup and show a "Successful creation" message. Instead of doing this it just shows "Please wait" loader for a second and then does nothing. There are no errors in the log and through remote debugging I confirmed that it doesn't enter the action method.
The weird thing is that when I run the same code in a local Tomcat installation it runs successfully. Also, on the remote server this application is deployed, this used to work just fine. All happened suddenly, and I have a lot of commandButtons like this one, across my application which still work great. Something seems to go wrong just with this particular page .
I use PrimeFaces 3.1 version, I dont know what other information is usefull to provide.
Any help/ideas is/are appreciated.
EDIT
This is userGroup.xhtml (the page whose buttons do not work) code:
<ui:composition
xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui"
xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:fn="http://java.sun.com/jsp/jstl/functions"
xmlns:comps="http://java.sun.com/jsf/composite/components"
template="/WEB-INF/templates/userGroup/edit.xhtml">
<f:metadata>
<f:event type="preRenderView" listener="#{userGroupBean.initUserGroupUsersList}" />
</f:metadata>
<ui:define name="title">
User Group
</ui:define>
<ui:define name="centerUnit">
<h:form>
<h:panelGrid columns="3" styleClass="ui-messages-info ui-corner-all" rendered="#{not empty flash.messages_info}">
<span class="ui-message-info-icon"></span>
#{flash.messages_info}
</h:panelGrid>
<p:messages showDetail="true" globalOnly="true" />
<p:panel header="Settings">
<h:panelGrid columns="3" cellpadding="5">
<h:outputLabel for="title" value="User Group Title:" />
<p:inputText id="title" value="#{userGroupBean.userGroup.title}" />
<p:message for="title" />
</h:panelGrid>
</p:panel>
<p:panel header="Members">
<p:pickList value="#{userGroupBean.usersGroupUsersList}" var="user"
iconOnly="true"
converter="userConverter"
itemLabel="#{user.username}" itemValue="#{user}">
<f:facet name="sourceCaption">Available</f:facet>
<f:facet name="targetCaption">Participating</f:facet>
<p:column style="width:25%">
<p:graphicImage value="#{facesContext.externalContext.request.contextPath}/../file?thumbnail=&downloadPath=#{user.contactDetails.picture.downloadPath}" width="40" height="40" />
</p:column>
<p:column style="width:25%">
<h:outputText value="#{user.username}" />
</p:column>
<p:column style="width: 50%">
<h:outputText value="#{user.contactDetails.lastName} #{user.contactDetails.firstName}"/>
</p:column>
</p:pickList>
</p:panel>
<p:commandButton
action="#{userGroupBean.createOrUpdateItemAction}"
value="#{userGroupBean.actionCreateOrUpdateLabel}"
icon="iconDisk"
update="#form"
oncomplete="window.scrollTo(0,0);" />
<p:separator />
<p:outputPanel style="text-align:right" layout="block" rendered="#{!userGroupBean.userGroup.isNew() and userGroupBean.hasUserModifyUserGroupAuthority()}">
<h:panelGroup>
<p:commandButton value="Delete" title="Do you want to delete this user group?"
action="#{userGroupBean.deleteItemAction}"
update="#form"
icon="iconDelete" />
<p:commandButton value="Leave user group" title="I want to leave this user group"
action="#{userGroupBean.userInSessionLeavesUserGroupAction}"
update="#form"
icon="iconUserGo"/>
</h:panelGroup>
</p:outputPanel>
</h:form>
</ui:define>
The UserGroupBean.java:
#Controller("userGroupBean")
#Scope(value = "view")
public class UserGroupBean extends GenericBean<UserGroup> {
private static final long serialVersionUID = 1L;
final Log logger = LogFactory.getLog(getClass());
#Autowired
private SessionServiceImpl sessionService;
#Autowired
protected UserGroupService userGroupService;
#Autowired
protected UserService userService;
#Override
public String getPageCreateOrUpdate() { return "userGroup.xhtml"; }
#Override
public String getPageList() { return "../../my/userGroups.xhtml"; }
/** Wrapper method which calls getItem() */
public UserGroup getUserGroup() { return getItem(); }
/** Wrapper method which calls setItem() */
public void setUserGroup(UserGroup UserGroup) { setItem(UserGroup); }
protected UserGroup findItemById(Integer userGroupId) {
return userGroupService.findUserGroupById(userGroupId);
}
#Override
protected void resolveCreateRequest(HttpServletRequest req) {
logger.debug("UserGroupBean::resolveCreateRequest()");
setItem( userGroupService.initializeUserGroup("") );
}
#Override
protected String createItem() {
try {
if(!isValidUsersSelection(new ArrayList<User>(usersGroupUsersList.getTarget())))
return null;
List<Integer> userIds = new ArrayList<Integer>();
for(User user: usersGroupUsersList.getTarget())
userIds.add(user.getId());
userGroupService.saveUserGroup(getUserGroup(), userIds);
helperFacesContext.addInfoMessageToFlash("User Group successfully created.");
return getPageCreateOrUpdate()+"?action=update&id="+getItem().getId()+"&faces-redirect=true";
}
catch (Exception e) {
JsfUtils.error("There was an error", e.getMessage());
return null;
}
}
.....
}
And finally the UservConverter.java
#FacesConverter(value = "userConverter")
public class UserConverter extends GenericConverter {
final Log logger = LogFactory.getLog(getClass());
private UserDAO getUserDAO(FacesContext facesContext) {
// #Autowired gives null
return (UserDAO) FacesContextUtils.getWebApplicationContext(facesContext).getBean("userDAO");
}
/**
* converts the String representation of the key back to the Object
*/
#Override
public Object getAsObject(FacesContext context, UIComponent component,
String value) throws ConverterException {
logger.info("UserConverter::getAsObject("+value+")");
Integer userId = Integer.valueOf(value);
try {
return getUserDAO(context).findById(userId);
} catch(Exception e) {
throw new ConverterException(handleException(context,e.getMessage()));
}
}
NEW CLUE: When I restart the server and only after that, when I access this page and manage to create a user group before userGroup.xhtml is fully loaded, the user group is created just fine. If I restart the server and wait till the page is loaded and then create a user group again nothing happens. This problem will drive me crazy at the end.
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...