Update primefaces datatable on row selection - jsf

I have a <p:datatable> where the user can select the radio button corresponding to a row in order to update that row. As of now, I populate another datatable with the information to edit by having the user click a button that calls a method. However, I would like to have the second datatable populated right when the user clicks the radio button of their desired row.
<h:form id="dataForm">
<p:panel styleClass="center" id="dataPanel">
<!-- This is where the results of the search are displayed. -->
<p:dataTable id="metadataitems" var="result"
value="#{updateMetadataItemsBean.results}" styleClass="center"
resizableColumns="true"
selection="#{updateMetadataItemsBean.selectedMetadataItem}"
rowKey="#{result.rowKey}" rendered="#{updateMetadataItemsBean.show}">
<p:ajax event="rowSelectRadio" listener="#{updateMetadataItemsBean.prepareEdit}" />
<p:column headerText="Select Item to Update" selectionMode="single" update="dataForm"></p:column>
</p:dataTable>
</p:panel>
<p:panel styleClass="centered" id="dataPanel2"
style="font-size:.75em;">
<p:messages id="message2" showDetails="true" />
<p:dataTable value="" var="metadataitemsInput" id="editTable">
<!--This is what I want to update-->
</p:dataTable>
<p:commandButton id="submit" value="Submit"
action="#{updateMetadataItemsBean.edit}"
update="message2, dataForm:dataPanel" />
<p:commandButton id="delete" value="Delete"
action="#{updateMetadataItemsBean.delete}"
update="message2, dataForm:dataPanel" />
</p:panel>
</h:form>
I can't find a way to call my method as soon as the user clicks one of the radio buttons.
This is the method that its supposed to call:
public void prepareEdit(SelectEvent e) {
//set variables that are references by <p:inplace> in datatable
}

Related

On clicking a command button, 2 dialog boxes with same widgetVar are getting opened

I am using Primefaces in my JSF Web project and there is one situation where I want to render a command button on some condition and when it is rendered then on click of that command button, I want one dialog box to get opened. This dialog should consists of one dropdown and when any value is selected from the dropdown, then one form beneath that dropdown should appear with the form fields related to the value selected in the dropdown.
The code I am trying:
<p:dataTable id="paramTable" value="#{testDesignView.paramlist}" var="pr" scrollable="true" liveResize="true" resizableColumns="true" style="font-size:10px;margin-bottom:0 ;min-height:200px" scrollRows="3" scrollHeight="120" >
<f:facet name="header">
Parameters
</f:facet>
<p:column headerText="Key" style="width:141.406px;">
<h:outputText value="#{pr.key}" />
</p:column>
<p:column headerText="Value" style="width:197.594px;">
<p:inputText value="#{pr.value}" ondblclick="try{PF('op').show();}catch(e){};showPanel([{name:'selectedparam', value:'#{pr.key}'}]);" >
<p:ajax listener="#{testDesignView.updateStepRow(pr)}"
/>
</p:inputText>
<p:commandButton rendered="#{pr.key == 'Body'}" icon="pi pi-window-maximize" actionListener="#{testDesignView.viewApiBody(pr)}" update="tm:bodyDialog:tcApiBody" oncomplete="PF('bodydlg').show();" style="margin-left:10px;"/>
</p:column>
<f:facet name="footer">
<p:commandButton value="Advanced Settings" rendered="#{testDesignView.restFlag}" oncomplete="PF('authSettingsdlg1').show();"/>
</f:facet>
</p:dataTable>
<p:dialog header="Advanced Settings" widgetVar="authSettingsdlg1" resizable="false" modal="true">
<p:panel id="authTypePanel" style="width:1200px;height:500px">
<p:selectOneMenu id="authType" value="#{testDesignView.currentAuthType}" style="width:1020px">
<p:ajax event="valueChange" listener="#{testDesignView.loadAuthForm()}"/>
<f:selectItem itemLabel="Select" itemValue="" noSelectionOption="true" />
<f:selectItems value="#{testDesignView.authTypesDropdownList}" var="authTypeNm" itemLabel="#{authTypeNm}" itemValue="#{authTypeNm}" />
</p:selectOneMenu>
</p:panel>
<h:panelGrid columns="2" cellpadding="5">
<f:facet name="footer">
<p:commandButton value="Access Token" style="margin-top: 5px;"/>
<p:commandButton value="Cancel" style="margin-top: 5px;" oncomplete="PF('authSettingsdlg1').hide();"/>
</f:facet>
</h:panelGrid>
</p:dialog>
public void loadAuthForm() {
System.out.println("loadAuthForm method invoked");
System.out.println("currentAuthType selected--> "+currentAuthType);
}
What am I doing wrong and how I can avoid opening these 2 dialogs of same widgetVar on click of below command button which is rendered on one condition?
<p:commandButton value="Advanced Settings" rendered="#{testDesignView.restFlag}" oncomplete="PF('authSettingsdlg1').show();"/>
Also, the ajax value change listener method is not getting invoked when any value is selected from the select dropdown of the dialog box with widget var 'authSettingsdlg1'. and when the cross button of one dialog is clicked, it closes the other duplicate dialog too.
Also, How can I change the form values and load a form just below the dropdown in the dialog box on the basis of the value selected from dropdown? for eg: if Basic is selected from dropdown, then form below it should get opened with 2 input text boxes fields of basic username and basic password. Similarly other form fields in dialog will change as per the selected value in dropdown.
Screenshot of 2 duplicate dialogs of same widgetVar

PrimeFaces components not updated even after using update attribute

I have 2 pages. Page 1 shows list of users in a datatable with 2 buttons for creating new user and editing existing user. On click of create and edit button both, a pop-up is opened(Page2) with a inputbox and a save button.
The issue that I am facing is if I click create(on Page1), Page2 opens. If I input something in the inputbox name, click cancel and then select an existing row in the datatable on Page1 and click edit,Page2 is opened again and whatever I inputted on create button click is retained and the PrimeFaces component is not updated even though I catch the dialog's onClose event on click of cancel button and reinitialize my view objects.
Page1:
<ui:composition template="template.xhtml>"
<ui:define name="center" >
<h:form id="myForm1">
<h:panelgroup id="panel1">
<p:datatable ..... />
This datatable shows list of users
<p:panelGrid id="buttonMenu1" >
<p:commandButton id="Create" actionListener="#{myBean1.onCreate}" oncomplete="PF('id2Var').show();" update=":myForm2" />
</p:panelGrid>
</h:panelGroup>
</h:form>
</ui:define>
<ui:define name="dialog">
<ui:include src="Page2" />
</ui:define>
</ui:composition>
Page2:
<p:dialog id="id2" widgetVar="id2Var" >
<p:ajax event="close" listener="#{myBean.onClose}" update=":myForm2" />
<h:form id="myForm2">
<h:panelgroup id="panel2">
<p:outputLabel value="Name" />
<p:inputText id="name" value="myBean.myList.name" />
<p:panelGrid id="buttonMenu" >
<p:commandButton id="Save" actionListener="#{myBean.onSave}" update=":myForm2" />
<p:commandButton id="Cancel" actionListener="#{myBean.resetInput}" update=":myForm2" oncomplete="PF('id2Var').hide();" />
</p:panelGrid>
</h:panelgroup
</h:form>
</p:dialog>

Primefaces datatable update datatable

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.

Primefaces DataTable - deleting with dialog deletes wrong entry

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.

JSF render is not working for form element

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.

Resources