how to show an image in p:dialog from a datable - jsf

I'm using primefaces to show a datable :
I have a column in my datable , it's an image , what i want is when i clic in the image , a p:dialog show the image with a big dimension .
I did it but the p:dialog show the wrong image, it shows the image of the last row in the datable .
<p:column headerText="imagePath">
<h:graphicImage library="images" name="#{book.imagePath}.png"
width="75px" onclick="PF('dlg').show();"/>
<p:dialog widgetVar="dlg" resizable="f" height="600px"width="500px"onShow="js">
<h:graphicImage library="images" name="#{book.imagePath}.png"width="400px"/>
</p:dialog>
</p:column>
Thank you
I have solved the problem with the commandlink component
<p:column headerText="imagePath">
<p:commandLink update=":zaki:foo:imgDlg1" oncomplete="dlg1.show()"
action="#{jsfClient.showImg(book)}">
<h:graphicImage value="/resources/images/#{book.imagePath}.png" width="75px"/>
</p:commandLink>
</p:column>
I have put in image into a commandlink and it works perfect , note that i have put the p:dialog out from the datable.

You should poll the dialog out of the dataTable and record which book did the user select before open the dialog.
Take a look at this code:
<p:dataTable value="#{imgBean.books}" var="book">
<p:column headerText="imagePath">
<h:commandButton image="/images/#{book.imagePath}.png" style="width: 75px" action="#{imgBean.showImg(book)}"/>
</p:column>
</p:dataTable>
<p:dialog widgetVar="dlg" id="imgDlg" resizable="f" height="600px" width="500px">
<h:graphicImage value="../images/#{imgBean.selectedBook.imagePath}.png" width="400px"/>
</p:dialog>
The action of the commandButton looks like:
private Book SelectedBook;
public void showImg(Book book){
this.SelectedBook=book;
RequestContext.getCurrentInstance().update("imgForm:imgDlg");
RequestContext.getCurrentInstance().execute("PF('dlg').show()");
}
public Book getSelectedBook() {
return SelectedBook;
}
In this way, you can not only show the image but also other information of the book.
BTW, you can also update/show the dialog in the h:commandButton instead of from backing Bean.

This is common widgetvar conflict. Think about how many p:dialogs are rendered in datatable and what is widgetvar of each? Inspect your rendered page to get better idea.
To resolve this issue either use some image id and pass it to custom javascript or create property (ex. "selectedBookImage") in your baking bean and refer it from <p:dialog>
. Using this technique you can easily move p:dialog outside datatable.

Related

How to update main form when data from dialog is changed?

We have a main window (MainScreen.xhtml) and a dialog box (DialogScreen.xhtml) in 2 separate files.
In MainScreen.xhtml, there is a link that calls and opens DialogScreen.xhtml. Also, there is a field called fieldA. fieldA's value is updated depending on selected value from DialogScreen.
MainScreen.xhtml sample:
<h:outputText value="#{bean.fieldA}" id="fieldA"/>
DialogScreen.xhtml sample:
<cf:autoComplete id="someId" autoCompleteList="#{someBean.listItems}">
<p:ajax event="itemSelect" update="someId"/>
</cf:autoComplete>
<p:commandLink id="setFieldA" action="{someBean.someAction}" value="set fieldA"/>
We tried the following but neither worked:
1. In DialogScreen.xhtml update commandLink:
<p:commandLink id="setFieldA" action="{someBean.someAction}" value="set fieldA"/>
<p:ajax event="itemSelect" update=":fieldA"/>
</p:commandLink>
Update MainScreen data by updating contextrequest in MainScreenBean.java
RequestContext.getCurrentInstance().update(":fieldA");
Both of the above fix resulted in error that :fieldA component cannot be found.
How to update the main form data when the dialog box data is changed?
I assume you have two form in two file. Make sure your dialog in DialogScreen.xhtml has appendTo="#(body)" this attribute set. It will append the html to the MainScreen.xhtml page. if your MainScreen.xhtml has
<h:form id='mainForm'>
<h:outputText value="#{bean.fieldA}" id="fieldA"/>
</h:form>
you can access update that field from DialogSceen.xhtml by
<h:form id="dialogForm">
<p:commandLink id="setFieldA" action="{someBean.someAction}" value="set
fieldA"/>
<p:ajax event="itemSelect" update=":mainForm:fieldA"/>
</p:commandLink>
</h:form>
So that means you have to put :formId:componentId to address any component outside of the form.

orderlist primefaces doesn't display the data

Is first time when I am trying to use primefaces orderList component.
I try to add some values in it. I am inserting values but the orderList component doesn't display anything.
Here is how my page looks:
Before using this component, I used a selectManyListBox which displays the data. And looking with the chrome's developer tools, the code is the same:
The code of orderList is:
<p:orderList id="choices" value="#{questionnaireExtendedKeyAttribute.extendedKeyAttributeChoices}" var="item" itemLabel="#{item.text}" itemValue="#{item.code}" controlsLocation="left" responsive="true">
<f:facet name="caption">Available</f:facet>
</p:orderList>
and the code for selectOneListBox is:
<h:selectManyListbox id="choices1" size="10" styleClass="form-control input-sm" style="float: left;" readonly="#{not questionnaireExtendedKeyAttribute.templateSessionData.notPublished}">
<f:selectItems value="#{questionnaireExtendedKeyAttribute.extendedKeyAttributeChoices}"/>
</h:selectManyListbox>
For the orderList I was looking here
Could you tell me where the problem is?
As you can see in the link, that you shared, you have to define columns for oderList. In your case:
<p:column>
<h:outputText value="#{item.text}" />
</p:column>

How to update a specific cell on a PrimeFaces dataTable

In my dataTable I am linking each article with a specific task.
On the click of a commandButton a list of tasks shows up, so I want on the select of a task, update a specific cell in the dataTable (outputText with id="columnTache") without updating the rest of my dataTable.
<p:dataTable value="#{myController.articleList}"
id="tabArticle"
var="article"
rowKey="#{article.id}" >
<p:column headerText="quantite" >
<pe:inputNumber value="#{article.quantite}" />
</p:column>
<p:column headerText="taches" >
<h:outputText value="#{article.tache.libelleTache}" id="columnTache" />
</p:column>
<p:column headerText="taches" >
<p:commandButton oncomplete="PF('dialogTasks').show();" update=":formSelectAffecterTache">
<p:ajax event="click" listener="#{myController.setArticle(article)}" />
</p:commandButton>
</p:column>
</p:dataTable>
<p:dialog header="#{bundleTech.lbl_taches}" widgetVar="dialogTasks" >
<h:panelGrid columns="1" >
<h:form id="formSelectAffecterTache">
<ui:include src="/pages/listTacheSelect.xhtml">
<ui:param name="bean" value="#{myController}" />
<ui:param name="action" value="affecterTache" />
</ui:include>
</h:form>
</h:panelGrid>
</p:dialog>
The update of my dataTable is in the managed bean:
public void affecterTache() {
article.setTache(selectedSingleTache);
RequestContext.getCurrentInstance().update("form:tabArticle");
}
A dataTable is a naming container, so components within it will be prepended with the dataTable's id. Also, each iteration of data presented in the table (each row) will have effect of the generated ids. Since a form is also a naming container, your outputText component ids will be generated as formId:tabArticle:0:columnTache in the first row, formId:tabArticle:0:columnTache in the second row, etc.
If you would set an id on your commandButton you will get formId:tabArticle:0:myButton, formId:tabArticle:1:myButton etc. You can use this id in your click handler to create the corresponding inputText clientId. But, since you pass article to a method, you are not able to check which button was clicked. So first of all change the click listeners method to:
public void useArticle(AjaxBehaviorEvent event) {
UIComponent component = event.getComponent();
}
Now, you know which button was clicked (event.getComponent()), but you need your article as well. You can set that as an attribute to your button in XHTML:
<p:commandButton id="myButton"
oncomplete="PF('dialogTasks').show();"
update=":formSelectAffecterTache">
<p:ajax event="click"
listener="#{myController.useArticle}" />
<f:attribute name="article"
value="#{article}" />
</p:commandButton>
This attribute can be read in your listener:
Article article = (Article) component.getAttributes().get("article");
Now, for updating the inputText, simply use the button's clientId:
String update = component.getClientId().replace(":myButton", ":columnTache");
Store it in your bean, and when you are ready to do so, update:
RequestContext.getCurrentInstance().update(update);
See also:
How to find out client ID of component for ajax update/render? Cannot find component with expression "foo" referenced from "bar"
Send additional parameter to Ajax event listener

Blocking a p:commandButton displayed on a p:confirmDialog in addition to displaying a dynamic message on the dialog

I'm trying to block a <p:commandButton> which is displayed on a <p:confirmDialog> as follows.
<p:confirmDialog id="confirmDeleteDialog" widgetVar="confirmDelete" message="Message" closeOnEscape="true" appendTo="#(body)" closable="true">
<p:blockUI block="confirm" widgetVar="blockUI">
<h:outputText value="Demo"/>
</p:blockUI>
<p:commandButton id="confirm" value="Yes" onstart="PF('blockUI').show()" oncomplete="PF('blockUI').hide();"/> <!--Use PF('confirmDelete').hide() to dismiss the dialog.-->
<p:commandButton id="decline" value="No" onclick="PF('confirmDelete').hide()" type="button" />
</p:confirmDialog>
<p:commandButton oncomplete="PF('confirmDelete').show()"/>
This blocks Yes button (one with the id="confirm") held by <p:confirmDialog>.
The message to be displayed on the confirm dialog is dynamic. It is fetched from the associated backing bean based on certain conditions. Therefore, the dialog is required to be updated before it is displayed.
To update the dialog before it is displayed, the update attribute of <p:commandButton> is set as follows.
<p:commandButton oncomplete="PF('confirmDelete').show()" update="confirmDeleteDialog"/>
This of course, displays a desired message on the dialog dynamically (which is not demonstrated here for the sake of simplicity) but doing so prevents the <p:blockUI> from functioning - it does not block the <p:commandButton>, if the dialog is updated by it.
Neither errors on the browser console nor exceptions on the server terminal are seen.
What is the way of blocking a button held by a in addition to displaying a dynamic message on the dialog?
EDIT :- the answer provided by me is cross-mark.
As noted in the answer given by me, <p/pe:blockUI> needs to be updated, when the <p:commandButton> held by the confirm dialog is clicked, it takes some time to block the button - <p:commandButton> after it is clicked. In the meanwhile, the button can be clicked (either deliberately or accidently) before the initial request completes that may cause duplicate submits which is certainly against the use of <p/pe:blockUI>.
Nothing is preventing a user in my workaround, from clicking the button multiple times before it is blocked by <p/pe:blockUI>. Therefore, the answer provided by me is considered to be cross-mark.
Perhaps the way to meet this requirement is completely different.
EDIT 2:- the actual scenario.
//A view scoped bean.
//A list of selected rows in <p:dataTable>.
private List<WishUtils>selectedValues;
//The actual message to be displayed on the dialog.
private String deleteMsg;
//Associated with the rendered property of the "Yes" button on the dialog.
private boolean renderedYesButtonDelete=true;
//The header message/text of the dialog.
private String messageBoxHeader;
//The no button text (its value).
private String noButtonTextDelete="No";
//Getters and setters as required.
public void confirmDelete(ActionEvent actionEvent) {
if(selectedValues!=null && !selectedValues.isEmpty()) {
renderedYesButtonDelete=true;
noButtonTextDelete="No";
deleteMsg="A long message about a delete prompt from a resource bundle";
messageBoxHeader="Confirm Delete";
} else {
noButtonTextDelete="OK";
renderedYesButtonDelete=false;
deleteMsg="Please select the rows you want to delete";
messageBoxHeader="Confirm Item Select";
}
}
public void delete(ActionEvent actionEvent) {
if(actionEvent.getComponent().getId().equals("confirmDeleteMultiple")) {
//Delete the selected rows.
} else {
//Notify an error (generally never going to be executed).
}
}
The message box goes here :
<p:confirmDialog id="confirmDialogDeleteMultiple" widgetVar="confirmDeleteUIWidget" header="#{wishManagedBean.messageBoxHeader}" closeOnEscape="true" appendTo="#(body)" closable="true">
<p:blockUI id="blockDelete" block="confirmDeleteMultiple" widgetVar="blockDeleteUIWidget"/>
<p:remoteCommand name="blockDeleteCommand" update="blockDelete" process="#this"/>
<p:commandButton id="confirmDeleteMultiple"
value="#{messages['confirmdialog.yes']}"
onclick="blockDeleteCommand();"
onstart="PF('blockDeleteUIWidget').show();"
oncomplete="PF('blockDeleteUIWidget').hide();PF('confirmDeleteUIWidget').hide()"
actionListener="#{wishManagedBean.delete}"
process="#this"
rendered="#{wishManagedBean.renderedYesButtonDelete}"
update="a list of components to be updated"/>
<p:commandButton id="declineDeleteMultiple"
value="#{wishManagedBean.noButtonTextDelete}"
onclick="PF('confirmDeleteUIWidget').hide()"
type="button"/>
<f:facet name="message">
<p:outputPanel>
<h:outputFormat value="#{wishManagedBean.deleteMsg}" escape="false"/>
</p:outputPanel>
</f:facet>
</p:confirmDialog>
The <p:blockUI> indeed fails when the entire dialog is updated. Looks like just another bug. It works when you explicitly call the PrimeFaces.cw(...) "create widget" script of the <p:blockUI> component (exactly that script which you see in generated HTML output representation of <p:blockUI>) on complete of the dialog update.
Given those IDs,
<h:form id="formId">
<p:confirmDialog id="confirmDialogId">
<p:blockUI id="blockId" ... />
<p:commandButton id="confirmButtonId" ... />
The following oncomplete should do it:
<p:commandButton update="confirmDialogId"
oncomplete="PrimeFaces.cw('BlockUI','blockUI',{id:'formId:blockId',block:'formId:confirmId'});PF('confirmDialogId').show()" />
That explains why the <p:remoteCommand> trick works as it under the covers basically re-generates the <p:blockUI> component along with that PrimeFaces.cw(...) call, although it fires an unnecessary ajax request. It might be worth reporting an issue to PrimeFaces guys, telling that PrimeFaces.cw(...) of <p:blockUI> isn't properly executed when the confirm dialog widget is updated.
Another workaround would be to explicitly ajax-update only the parts you'd like to update instead of the entire dialog. That works for me. The header and the message attributes of the <p:confirmDialog> (and those of many other PrimeFaces components) supports being defined via <f:facet> on the attribute name. This allows you to wrap it in a <h:outputText> (or <h:panelGroup>) so that you can just update it individually. This way you don't need to update the entire dialog and the block UI keeps working as intented.
<p:confirmDialog ...>
<f:facet name="header">
<h:outputText id="confirmDeleteDialogHeader" value="#{bean.header}" />
</f:facet>
<f:facet name="message">
<h:outputText id="confirmDeleteDialogMessage" value="#{bean.message}" />
</f:facet>
<h:panelGroup id="confirmDeleteDialogContent">
<p:blockUI ... />
<p:commandButton ... />
<p:commandButton ... />
</h:panelGroup>
</p:confirmDialog>
<p:commandButton ...
update="confirmDeleteDialogHeader confirmDeleteDialogMessage confirmDeleteDialogContent"
oncomplete="PF('confirmDelete').show()" />
This requires the <p/pe:blockUI> to be updated, when the <p:commandButton> displayed on the confirm dialog is clicked.
The <p:blockUI> can be updated onclick using the <p:remoteCommand> (onstart also works).
The code goes here.
<p:confirmDialog id="confirmDeleteDialog" widgetVar="confirmDelete" message="Message" closeOnEscape="true" appendTo="#(body)" closable="true">
<p:blockUI id="blockConfirm" block="confirm" widgetVar="blockUI"/>
<p:remoteCommand name="confirmCommand" update="blockConfirm"/>
<!--Add PF('confirmDelete').hide() to oncomplete to dismiss the dialog, when this button is clicked.-->
<p:commandButton id="confirm" value="Yes" onclick="confirmCommand();" onstart="PF('blockUI').show()" oncomplete="PF('blockUI').hide()"/>
<p:commandButton id="decline" value="No" onclick="PF('confirmDelete').hide()" type="button" />
</p:confirmDialog>
<p:commandButton oncomplete="PF('confirmDelete').show()" update="confirmDeleteDialog" value="Submit"/>

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