I have a composite displayed inside a dialog. I have an edit button that get the current bean #SessionScoped (item in a data table) and then update the UI. My app is very similar to a simple CRUD app like http://balusc.blogspot.com/2010/06/benefits-and-pitfalls-of-viewscoped.html.
The problem is that the UI is updated correctly when using <h:outputText/> but not when using a form element.
<h:inputTextarea value="#{cc.attrs.managedBean.assertionStatement}" />
<h:inputText value="#{cc.attrs.managedBean.assertionStatement}" />
<h:outputText value="#{cc.attrs.managedBean.assertionStatement}"/>
The UI shows an empty textarea and input but the outputText renders the correct value. The getAssertionStatement() is called 3 times which seems to be the correct behavior.
When I close the dialog and reopen it, everything (form element) is populated.
The dialog call (ag namespace is for composite component):
<p:dialog widgetVar="DataValueRuleDialog" modal="true" height="600" width="800">
<p:outputPanel id="DataValueRulePanel">
<ag:DataValueAssertion managedBean="#{dataValueAssertionController}" id="DataValueComposite" />
</p:outputPanel>
</p:dialog>
The composite that calls another composite:
<h:form id="DataValueForm">
<ag:assertionMetadataComponent
managedBean="#{cc.attrs.managedBean.dataValueAssertionBean.assertionMetadataBean}"
assertionStatementRows="5" />
<p:dataTable value="#{cc.attrs.managedBean.model}" var="item">
<p:column>
<f:facet name="header">Assertion Statement</f:facet>
<h:outputText rendered="#{item.profileBean.profileLocation == cc.attrs.managedBean.selectedComformanceProfile.name}" value="#{item.assertionMetadataBean.assertionStatement}" />
</p:column>
<p:column>
<p:commandButton rendered="#{item.profileBean.profileLocation == cc.attrs.managedBean.selectedComformanceProfile.name}" value="edit" immediate="true"
actionListener="#{cc.attrs.managedBean.editDataValueAssertion}" update=":DataValueComposite:DataValueForm">
</p:commandButton>
</p:column>
</p:dataTable>
</h:form>
When I remove the immediate=true the form is validated and since one of the required field (supposed to be populated) is missing, I got a validation error. This is why I have immediate=true but it should be necessary since all the items in the data table should be valid.
Related
I have a problem with primefaces datatables. I have one datatable with some entries and a column with a button inside. If the button is pressed a popup is opened with another datatable. The entries in the second datatable are depending on the row in which the button is pressed.
<!-- first datatable -->
<h:form id="list">
<p:dataTable id="list1" var="item" value="#{bean1.itemlist}"
rowKey="#{item.id}" selection="#{bean1.selectedItem}"
selectionMode="single">
<p:column headerText="ID">
<h:outputText value="#{item.id}" />
</p:column>
...
<p:column headerText="Edit Entries">
<p:commandButton value="Edit Entries"
actionListener="#{bean2.updateEntries(item)}" ajax="true"
oncomplete="PF('edit_entries').show()" />
</p:column>
</p:dataTable>
<!-- Second datatable in the popup -->
<p:dialog header="Edit Entries" widgetVar="edit_entries" modal="true"
resizable="false">
<p:dataTable id="list2" var="entry"
value="#{bean2.entriesList}" rowKey="#{entry.id}"
selection="#{bean2.selectedEntry}" selectionMode="single">
<p:column headerText="Entry Number">
<h:outputText value="#{entry.number}" />
</p:column>
</p:dataTable>
<f:facet name="footer">
<p:commandButton value="Save" oncomplete="PF('edit_entries').hide()" />
</f:facet>
</p:dialog>
</form>
Bean2
public void updateEntries(Item selectedItem) {
this.entriesList = this.entriesQuery.getAllEntriesByItemID(selectedItem.getId());//db query could take some time
System.out.println("entrieslist size: " + this.entriesList.size()); //prints the correct size
}
The problem is that there are no entries listed in the popup datatable although there are some in the list after the db query.
Any ideas how to fix this bug?
Thanks in advance!
UPDATE 1:
<!-- first datatable -->
<h:form id="list">
<p:dataTable id="list1" var="item" value="#{bean1.itemlist}"
rowKey="#{item.id}" selection="#{bean1.selectedItem}"
selectionMode="single">
<p:column headerText="ID">
<h:outputText value="#{item.id}" />
</p:column>
...
<p:column headerText="Edit Entries">
<p:commandButton value="Edit Entries" update=":dialogUpdateEntries"
actionListener="#{bean2.updateEntries(item)}" ajax="true"
oncomplete="PF('edit_entries').show()" />
</p:column>
</p:dataTable>
</h:form>
<!-- Second datatable in the popup -->
<p:dialog header="Edit Enries" id="dialogUpdateEntries" widgetVar="edit_entries" modal="true"
resizable="false">
<h:form id="formEntriesList">
<p:dataTable id="list2" var="entry"
value="#{bean2.entriesList}" rowKey="#{entry.id}"
selection="#{bean2.selectedEntry}" selectionMode="single">
<p:column headerText="Entry Number">
<h:outputText value="#{entry.number}" />
</p:column>
</p:dataTable>
<f:facet name="footer">
<p:commandButton value="Save" oncomplete="PF('edit_entries').hide()" />
</f:facet>
</form>
</p:dialog>
You're indeed not updating the data table in the dialog. JSF doesn't automatically update the view on change of the model, you have to explicitly tell the view to do so. You can use the ajax action component's update attribute for this. This takes a JSF client ID which can be found by rules as outlined in this related answer: How to find out client ID of component for ajax update/render? Cannot find component with expression "foo" referenced from "bar".
Given the markup as shown in the question, that'll be
<p:commandButton ... update=":list:list2" />
However, there's another potential problem. You're using <p:dialog modal="true"> inside a form instead of giving the dialog its own form. This way the dialog may not be available in the HTML DOM tree as JavaScript (the one responsible for dealing with ajax stuff) would expect to find it. Giving the dialog its own form should fix this matter. It'll also fix the potential future problems with invoking actions from inside the dialog as handled in this related question: <p:commandbutton> action doesn't work inside <p:dialog>.
<h:form id="viewForm">
...
<p:commandButton ... update=":editDialog" />
...
</h:form>
<p:dialog id="editDialog" modal="true">
<h:form id="editForm">
...
</h:form>
</p:dialog>
Try adding update="list2" to Edit Entries command button (even update="#widgetVar(edit_entries)" should work).
If, because of page layout and structure, you can't target the second datatable using above suggestions, then add styleClass="tList2" to second table, and update it with update="#(.tList2)" on edit button.
I have a table in a form. One of the columns in the table displays a row of buttons to edit and delete the table entries. When I delete an entry callign the controller from a button's action attribute, it works as expected.
But once I have added a dialog to let the user confirm the deletion, a wrong entry is deleted. It is always the last entry in the current table. I have no idea what the reason could be - I am using the same DataTable var for the button and for the dialog.
I am working with JSF 2 (Mojarra 2.1.6) and Primefaces 3.5 deploying on JBoss 7.1.1 on a Suse 12.2 machine.
The form:
<h:form id="downloads">
<ui:include src="components/table.xhtml"/>
</h:form>
The table:
<ui:composition>
<p:dataTable value="#{controller.currentLevelResources}"
var="download" id="downloadTable" scrollHeight="120" rows="10">
<p:column sortBy="#{download.name}">
<f:facet name="header">Name</f:facet>
<h:outputText id="downloadName" value="#{download.name}" title="#{download.description}" />
</p:column>
...
<p:column>
<ui:include src="menuBar.xhtml"></ui:include>
</p:column>
The menu bar:
<ui:composition>
<p:commandButton id="edit"
action="#{downloadEditController.editResource(download)}"
icon="ui-icon-gear" title="Edit" oncomplete="updateStyles()"
update=":downloads" />
<p:commandButton id="delete" onclick="deletedDlg.show();"
icon="ui-icon-trash" title="Delete" oncomplete="updateStyles()" />
<p:dialog header="Delete confirmation" widgetVar="deletedDlg"
resizable="false">
<h:panelGroup layout="block" style="padding:5px;">
<h:outputText
value="The Resource #{download} will be deleted. Proceed?" />
</h:panelGroup>
<p:commandButton id="deleteBtn" value="Delete"
oncomplete="deletedDlg.hide(); updateStyles(); "
action="#{downloadEditController.deleteResource(download)}"
process="#this" update=":downloads">
</p:commandButton>
<p:commandButton value="Cancel" type="button"
onclick="deletedDlg.hide();" />
</p:dialog>
If I replace the dialog with this, everything works:
<p:commandButton id="delete" icon="ui-icon-trash" title="Delete"
action="#{downloadEditController.deleteResource(download)}"
oncomplete="updateStyles()" update=":downloads" />
Creating a <p:dialog> for every row is not a good idea.
For starters you had better create a single <p:dialog> outside your <p:dataTable>.
Next thing that I would do is to set the id or the row var in your bean upon delete button click and in case of confirmation in dialog use that id or the row var from bean to delete.
This is how your delete button could look like, set the download var in prepareDataForDeletion action and show the dialog...
<p:commandButton id="deleteConfirmation" icon="ui-icon-trash" title="Delete"
action="#{downloadEditController.prepareDataForDeletion(download)}"
onsucess="deletedDlg.show();"/>
Regarding your current anomaly: it's because all your dialogs have the same widgetVar and each next one is overriding the previously declared one all the way until the last one. You could dynamically give them a different widget names like so widgetVar="deleteDlg_#{someIndex}", but this makes no sense if you can have just only one reusable dialog whose content is updated before opening.
I have a page where I ask the user to input a value into a inputText box. Based on the entered value I create a datetable with information from my database. One of the columns in the datatable is a selectOneRadio therefore each row has its own radio button. The user should then be able to select one of the radio buttons and then click a commandbutton (which is the footer of the datatable) that will obtain which row is selected based on which radio button is selected. The problem that I am having is upon the button click the backing bean method isn't being called. This issue only happens when i create the table after going to the page. if i hard code a value to cause the datatable to exist at the creation of the page this problem does not happen. I'm not completely sure but I believe this problem is happening because the datatable rendered is initially set to false and for some reason this is effecting either the binding or the valueChangeListener some how.
This is the jsf
<h:panelGrid columns="3">
<h:outputLabel for="searchByContrId" value="Company Code: " />
<h:inputText id="searchByContrId" value="#{applContAdminB.searchContrId}">
</h:inputText>
<h:commandButton type="submit" value="Search" id="submitSearch" action="#{applContAdminB.getEmployeesByContrId}" />
</h:panelGrid>
<br />
<h:outputText rendered="#{applContAdminB.contrIdEntered}" value="Current Administrator: " />
<h:outputText value="#{applContAdminB.adminName}" />
<h:dataTable id="empTable" var="loc" rendered="#{applContAdminB.contrIdEntered}" value="#{applContAdminB.employeesListModel}" binding="#{applContAdminB.htmlDataTable}">
<h:column>
<h:selectOneRadio onclick="updateRadioButtons(this);" valueChangeListener="#{applContAdminB.setSelectedRow}">
<f:selectItem itemValue="null" itemLabel="" />
</h:selectOneRadio>
</h:column>
<h:column>
<f:facet name="header">Employee Name</f:facet>
<h:outputText value="#{loc.empName}" />
</h:column>
<h:column>
<f:facet name="header">Employee Email</f:facet>
<h:outputText value="#{loc.empEmail}" />
</h:column>
<h:column>
<f:facet name="header">Status</f:facet>
<h:outputText value="#{loc.userStatus}" />
</h:column>
<f:facet name="footer">
<h:panelGrid columns="2">
<h:commandButton type="submit" id="transferRights-submit" value="Transfer Rights" action="#{applContAdminB.adjustAdminUser}" />
</h:panelGrid>
</facet>
</h:dataTable>
you answered your own question. this is a weakness in using rendered with ajax. i had a similar issue with a navigation widget i had that toggled the attribute that rendered was bound to via ajax. no manner of magic i could muster would get the invisible panel to render while hiding the panel that was initially rendered. you might try just hiding the div via javascript and when your ajax returns twiddle the "display" attribute of the div(s) accordingly. that's how i solved it. it's unfortunate, but i could not find an alternate solution that was desirable. – him
I use a Primefaces carousel component to display a list of items. What i would like to do is show a commandButton on every carousel item which triggers a method on the bean to confirm or decline the entry.
Now it works only for the first entry of the carousel. Clicking on another entry does not invoke the action confirmResource. I guess it has something to do with the IDs but i can't figure it out.
Here's the form:
<h:form id="form" prependId="false">
<p:carousel id="resourceCarousel" value="#{resourceRatingBean.resourceProposalList}" var="var" rows="1" itemStyle="width:500px; height: 400px; text-align:center;" circular="true">
<p:column>
<h:panelGrid columns="1" cellpadding="3">
<p:graphicImage value="/cache/images/#{var.imagePath}" width="100"/>
<h:outputText value="#{var.imagePath}" />
<h:outputText value="#{var.name}" />
<h:outputText value="#{var.description}" />
</h:panelGrid>
<p:commandButton value="confirm" action="#{resourceRatingBean.confirmResource}" process="#this">
<f:setPropertyActionListener value="#{var}" target="#{resourceRatingBean.ratedResource}" />
</p:commandButton>
</p:column>
</p:carousel>
</h:form>
I see two likely problems here:
The process="#this" is likely an issue as this will only invoke the process of the invoke the action of the commandButton and not the changes in the carousel component. Try setting this attribute to resourceCarousel or #form instead.
If you are still having issues and using JSF 2 + EL 2.2, then instead of depending on setPropertyActionListener to set the value of a managed property, then instead you can pass the argument var to an actionListener method through an EL expression.
Here is an example:
<p:commandButton value="confirm" actionListener="${resourceRatingBean.confirmResourceListener(var)}"
this="resourceCarousel" />
I am trying to submit values in a pop-up panel inside another panel that has a submit/action event. But before opening pop-up panel I need to invoke a function on my managed bean that create a new entity object. The outer panel has the only h:form, since you can't nest them. I have wrapped the pop-up panel in a a4j:region to submit only this part when the use submits the values inside the pop-up panel. This works, but not the execution of the preparing function that need to be invoked when the pop-up panel executes. I have tried a4j:commandLink but that component don't work together with the rich:popupPanel (strange since both of them are Richfaces components?!). So I have to relay on the h:commandLink and use ajax.
How can I invoke a function on my managed bean when the link to open/render the pop-up panel fires?
(What is the correct pattern for this?)
PS. The initial question has changed, but not the problem concerning submitting values in a pop-up panel.
Part of the xhtml file:
<h.form>
...
<a4j:region>
<rich:popupPanel id="popup_sys_user_req" modal="false" autosized="true" resizeable="false">
<f:facet name="header">
<h:outputText value="Request New Sector/Category" />
</f:facet>
<f:facet name="controls">
<h:outputLink value="#"
onclick="#{rich:component('popup_sys_user_req')}.hide(); return false;">
X
</h:outputLink>
</f:facet>
<h:panelGrid columns="2">
<h:outputLabel value="Request New:" />
<h:selectOneMenu id="sys_req_type" value="#{userController.selectedSysUserRequest.sysrequesttype}" required="true" >
<f:selectItems value="#{userController.getSysRequestTypeItems('SECTOR_CATEGORY')}">
</f:selectItems>
</h:selectOneMenu>
<h:outputLabel value="Description:" />
<h:inputTextarea id="user_req_desc" value="#{userController.selectedSysUserRequest.description(desc)}" required="true" requiredMessage="Decription is missing" />
</h:panelGrid>
<a4j:commandButton action="#{userController.CreateSysUserRequest()}" value="Send Request" execute="sys_user_req_form" oncomplete="#{rich:component('popup_sys_user_req')}.hide(); return false;"/>
</rich:popupPanel>
</a4j:region>
</h:form>
The commandLink (re-edit)
<h:commandLink actionListener="#{userController.prepareCreateSysRequest}" value="Request New Sector/Category">
<f:ajax execute="popup_sys_user_req #this" render="popup_sys_user_req">
<rich:componentControl id="popup_ctr" event="click" target="popup_sys_user_req" operation="show"/>
</f:ajax>
</h:commandLink>
----------------------------
//Managed Bean:
public void prepareCreateSysRequest(ActionEvent event ) {
selectedSysUserRequest = new Sysuserrequest();
JsfUtil.log("Prepare Create System User Request");
}
This post continues the dicussion about the pop-up panel.
Greetings Chris.
If I understand correctly you want to submit all form elements inside popupPanel but not outside the panel when you invoke someAction1? I can think of two ways to do this:
1. a4jcommandButton has a limitToList attribute, you can list which components you want to be updated on the server
2. create your popupPanel outside of the first form and then use its own form:
<h:form>
...
<a4j:commandButton action="someAction2"...
</h:form>
<rich:popupPanel>
<h:form>
...
<a4j:commandButton action="someAction1"...
</h:form>
</rich:popupPanel>
Update
If you are using RichFaces 4 you can replace the limitToList attribute with limitRender
The problem is that the popup isn't a child of the form in jsf, you only need to use the domElementAttachment attribute to change that. So your code would look like this:
<h.form>
...
<a4j:region>
<rich:popupPanel id="popup_sys_user_req" modal="false" autosized="true" resizeable="false" domElementAttachment="form">
<f:facet name="header">
...