I'm using Primefaces TabView, CommandButton and FileDownload to download a log file. Once the log file has been downloaded, I want to offer the option to delete the contents of the log from the server.
Initially the Delete Log File Button (deleteEventLogButton) is disabled and has a custom caption stating "Delete Logs - Export Required". Once the log has been exported, the button should be enabled and the caption should state "Delete Logs".
The problem that I'm having is that the Delete Log File Button is still disabled and the caption reads "Delete Logs - Export Required" even after the Export event completes successfully.
My guess is that the exportEventLogButton->Update="deleteEventLogButton" is being called before the fileDownload value.
Once I've exported the logs, I can hit 'F5' and refresh the page and the deleteEventLogButton is enabled showing the correct caption.
JSF - Snippet
<p:tabView id="logView">
<p:tab id="eventLogTab" title="Security Events">
<p:panelGrid ...>
<p:commandButton id="exportEventLogButton" icon="ui-icon-disk" styleClass="c25" ajax="false" title="Export Log" disabled="#{empty managedCmsLogsBean.eventLogEntityList}" update="deleteEventLogButton">
<p:fileDownload value="#{managedCmsLogsBean.exportEventLogFiles()}"/>
</p:commandButton>
<p:commandButton id="deleteEventLogButton" icon="ui-icon-trash" styleClass="c25" ajax="false" title="#{managedCmsLogsBean.deleteEventLogCaption}" disabled="#{! managedCmsLogsBean.eventLogExported}" action="#{managedCmsLogsBean.clearEventLogs()}" update="eventLogTab" />
</p:panelGrid>
<p:dataTable value="#{managedCmsLogsBean.eventLogEntityList}" ...>
...
</p:dataTable>
</p:tab>
</p:tabView>
Backing Bean - Snippet
private boolean eventLogExported;
public StreamedContent exportEventLogFiles() {
eventLogExported = true;
return logFileUtility.exportSecurityEventLog(eventLogEntityList, eventLogStartDate, eventLogStopDate);
}
public boolean isEventLogExported() {
return eventLogExported;
}
public void setEventLogExported(boolean value) {
eventLogExported = value;
}
public String getDeleteEventLogCaption() {
return eventLogExported ? "Delete Logs" : "Delete Logs - Export Required";
}
I tried moving the update event inside the FileDownload, but it didn't make a difference.
<p:commandButton id="exportEventLogButton" icon="ui-icon-disk" styleClass="c25" ajax="false" title="Export Log" disabled="#{empty managedCmsLogsBean.eventLogEntityList}">
<p:fileDownload value="#{managedCmsLogsBean.exportEventLogFiles()}">
<p:ajax update="deleteEventLogButton"/>
</p:fileDownload>
</p:commandButton>
I've searched for a couple of days now and have found MANY problems that come very close to this one... but none that have helped. :(
Just to make things very clear... I am NOT having problems with the export. The problem is that the Delete Log File Button is not enabled after the export is complete.
p:commandButton in your case is (an has to be) non-AJAX button (you set this by adding ajax="false" attribute). In that case update attribute and p:ajax tag doesn't have any sense (as they are only for AJAX requests). When you have file download your application sends streaming of some type, and you see Save File dialog. Your page is not refreshed. So you have to use PrimeFaces.monitorDownload to do this:
<p:commandButton id="exportEventLogButton"
icon="ui-icon-disk"
styleClass="c25"
ajax="false"
title="Export Log"
disabled="#{empty managedCmsLogsBean.eventLogEntityList}"
onclick="PrimeFaces.monitorDownload(null, stop)">
and add stop function which will update second button:
<p:remoteCommand name="stop" update="deleteEventLogButton"/>
As Balusc answered, In question (revisions) , we cannot get response twice from a single request, to refresh a page after download, better use the following java script in download link(p:commandbutton) onclick tag.
Example:
<p:commandButton ajax="false" icon="ui-icon-arrowstop-1-s" onclick="setTimeout('location.reload();', 1000);" action="#{managedBean.downloadMethod}" />
this will automatically refresh the page after 1 second, at the same time i.e. before refresh, you will get the download file, based on your download response time, increase the seconds in that script. Seconds should not less than that download response time.
From PrimeFaces 10, you are able to download files with ajax="true". This allows you to update components as well.
See also:
https://primefaces.github.io/primefaces/10_0_0/#/components/filedownload?id=ajax-downloading
https://github.com/primefaces/primefaces/issues/5978
Have you tried changing eventLogExported/isEventLogExported from boolean to Boolean or String ?
Related
I have a <p:datable> to display some products items. One of the item is a <p:graphicImage>. I would like to make this image clickable and display image in bigger in a popup when the image is clicked. Note that the images are stored in a database.
I've tried something like that:
<h:commandLink id="imageBtn"
action="#{imageBean.showImg(_product.id)}">
<p:graphicImage id="product_thumbnail" styleClass="thumbnail"
cache="false"
value="#{imageBean.streamedImageById}">
<f:param name="productId" value="#{_product.id}" />
</p:graphicImage>
</h:commandLink>
...
<p:dialog id="imgDialog" header="Image in Bigger" widgetVar="imgDialog">
<p:graphicImage styleClass="thumbnail_large" cache="false"
value="#{imageBean.getImageById()}">
</p:graphicImage>
</p:dialog>
in my ImageBean:
public void showImg(Long id) {
this.currentProductId = id;
PrimeFaces.current().executeScript("PrimeFaces.widgets['imgDialog'].show();");
}
public StreamedContent getImageById() throws Exception {
if (currentProductId != null) {
..
}
}
The image is clickable and popup correctly displayed, but for some reasons the full data table is refreshed (including all the images) after clicking, which is not user-friendly. Do you have any idea about my problem?
If you are not using Ajax, your entire page will be rerendered if you click a command link. You might want to replace your h:commandLink with a p:commandLink which gives you Ajax out of the box. Then, you want to rerender the dialog when that button is clicked (in order to contain the correct image) and simply show the dialog from the client side using the oncomplete attribute:
<p:commandLink action="#{imageBean.setCurrentProductId(_product.id)}"
update="imgDialog"
oncomplete="PF('imgDialog').show()">
...
</p:commandLink>
Please note that it's important that you choose the right bean scope. Ajax will not work with #RequestScoped beans. You probably want to use #ViewScoped.
So I have this code:
<h:form id="serviceCustomFormForm">
<p:dialog id="parameterGroupAddDialog" widgetVar="parameterGroupAddDialog" header="#{messages.addParameterGroup}" modal="true" resizable="false">
<p:inputText value="#{serviceCustomFormBean.serviceParameterGroup.name}" styleClass="Wid90" />
<br />
<br />
<p:commandButton value="#{messages.save}" styleClass="Fright BlueButton" update="serviceCustomFormForm" actionListener="#{serviceCustomFormBean.addServiceParameterGroup}" oncomplete="PF('parameterGroupAddDialog').hide()" />
<p:commandButton value="#{messages.cancel}" styleClass="Fright RedButton" oncomplete="PF('parameterGroupAddDialog').hide()"/>
</p:dialog>
<div class="Container100">
<div class="ContainerIndent">
<p:commandButton value="#{messages.addParameterGroup}" icon="fa fa-plus-circle" styleClass="Fright CyanButton FloatNoneOnMobile" oncomplete="PF('parameterGroupAddDialog').show()" />
<div class="EmptyBox10 ShowOnMobile"></div>
</div>
</div>
</h:form>
When the page is first loaded the #PostConstruct method is called.
When I click the commandButton to open the dialog it's called again. And when I press the Cancel button inside the dialog it's called again.
This behavior does not occur in other parts of the application, and I can't see what I am missing here.
Update: As requested, the Bean code is here:
#ManagedBean
#ViewScoped
public final class ServiceCustomFormBean implements Serializable {
private ServiceParameterGroup serviceParameterGroup = new ServiceParameterGroup();
// Other attributes
#PostConstruct
private void init() {
// Reads attributes sent from previous page
}
public void addServiceParameterGroup() {
// Saves the serviceParameterGroup to database
}
// Getters and Setters
}
It's because the Commandbutton submits the form. You can
change to this:
<p:commandButton type="button" ...onclick="PF('parameterGroupAddDialog').hide()"
Type button tells primefaces not to submit the form. If the form isn't submitted oncomplete is never called. So it's onclick.
Try setting the following attributes to your 'Add Service' and 'Cancel' commandButton elements: partialSubmit="true" process="#this".
Code like this:
<commandButton value="#{messages.addParameterGroup}" ... partialSubmit="true" process="#this" ... />
By default, pf commandButtons try to submit the whole form, while in those two cases you just want to call the invoked method without doing a submit. With this, you are saying to primefaces that you don't want to submit it all (partialSubmit=true), and that you just want to process the invocation of the button itself (process=#this). Maybe that is your problem.
As an additional comment, i don't think getting the label values for the buttons from the bean is a good idea (unless you want to intentionally change the labels dynamically), because you will end up doing excessive requests to the bean. Better try using a messages properties file, as described in here http://www.mkyong.com/jsf2/jsf-2-0-and-resource-bundles-example/.
If I remember correctly, you should put your Dialog outside your main form, at the end of your body or use the appendTo="#(body)" param, and then, have another form inside the dialog.
After a long time dealing with this problem, I finally found the reason.
The annotation ViewScoped that I was importing in the backing bean was from the package javax.faces.view.
The correct one is javax.faces.bean.
Thanks for everyone that spend some time trying to help.
here is my commandButton:
<p:commandButton value="Foo" update="panel1,panel2"
action="#{fooBean.add()}" />
method fooBean.add() is checking if object i want to add is not already in database - it return true - if it is already in base, false if it is not.
what i want to do is display a success message if fooBean.add() will return false after click on button.
It would be nice if that message would be like ConfirmDialog with OK option to close poped out window. Something like this:
http://www.primefaces.org/showcase/ui/confirmDialog.jsf
Any ideas how to help me?
If I understand you correctly you just want to display a dialog, so that the user acknowledges that the action succeeded. You could simply use a growl, but here is a solution using your approach.
.xhtml
<p:commandButton value="Foo" action="#{fooBean.add()}" />
<p:dialog widgetVar="dialog" modal="true">
<p:commandButton value="Ok" icon="ui-icon-close" oncomplete="dialog.hide()" />
</p:dialog>
fooBean
public void add() {
// do stuff
if(isInDB)
RequestContext.getCurrentInstance().execute("dialog.show()");
}
This opens the dialog after your item has already been found in the database. Nevertheless it may be more convenient for the user if he'd get a more subtle notification, without extra clicks.
I am trying to develop a Billing application using JSF and PrimeFaces. The basic functionality requires to add several items to a bill and click the update button when the bill is complete. The printed bill must include details like BillId which is generate at the end of the backing bean settleBill method. It is needed to do it in one page so that after the print, the application is ready for a new bill.
I developed that as follows, but Printing and executing the method do not happen as expected.
<p:commandButton value="Settle" action="#{billController.saveSelected()}" ajax="false" >
<p:printer target="pDetails" />
</p:commandButton>
When I use without Ajax, Printing part is ok, but action is not executed. When used with Ajax, command is executed, but print is not working. I used an action listner instead of the action, still the same result.
<p:commandButton value="Settle" actionListener="#{billController.settleBill}" ajax="false" >
<p:printer target="pDetails" />
</p:commandButton>
How can I execute a backing bean method at the same time getting printouts with final values like Bill Id, which is generated after the backing bean method is fully executed. I want to achieve it in a single page so that after every bill the screen is ready for the next bill.
Thanks in advance.
When you use without Ajax, To make printing as well as action to work you have to use following code:
<p:commandButton value="Settle" actionListener="#{billController.settleBill}">
<f:ajax execute="#this"/>
<p:printer target="pDetails" />
</p:commandButton>
and In the settleBill method declare it with ActionEvent like below:
public void settleBill (ActionEvent actionevent) {}
<p:remoteCommand name="rc" actionListener="#{movimentoBean.test}" />
<p:commandButton value="Imprimir" type="button"
icon="ui-icon-print" onclick="rc();PF('visDialog').hide()"
style="display:block;margin-bottom: 20px">
<p:printer target=":formMovimentos:etiqueta" />
</p:commandButton>
public void test(ActionEvent actionevent) {}
I'm using JSF 2.0, Primefaces 3.4.2, Spring 3.1.2.
I'm facing a similar problem of the guy of this link: h:commandButton works from the second click.
Like him I'm not using ajax in the <p:commandButton> but I'm using a <p:fileDownload /> inside the button tag.
I have two views: "list.xhtml" and "downloadView.xhtml". In myBean.java I send a DataModel from view "list.xhtml" to view "downloadView.xhtml" as a request attribute as shown in the code below:
FacesUtil.getServletContext().setAttribute("myDataModelFromRequest", this.myDataModel);
The bean is anotted with #Scope("view")
In view "downloadView.xhtml" I populated succesfully a dataTable with the DataModel sent from request. But the problem happens when I click in the button to download the file. It only works on second try.
I already tried to change the return of my method from null to "downloadView" but the problem was not solved.
In debug mode I noticed that only enter in the "downloadMethod()" on second click.
Anyone have an idea to solve it?
myBean.java
public String viewListMethod() {
//some work here...
FacesUtil.getServletContext().setAttribute("myDataModelFromRequest", this.myDataModel);
return "downloadView";
}
downloadView.xhtml
<h:form id="formId" prependId="false">
<p:dataTable
id="dataTableId" var="myVar" value="#{myDataModelFromRequest}"
selection="#{cargaProcessoControlador.myArray}"
paginator="true" rows="10" paginatorPosition="bottom" paginatorAlwaysVisible="false">
<f:facet name="header">
bla bla bla
</f:facet>
<p:column selectionMode="multiple" style="width:18px" />
//collumns here...
</p:dataTable>
<p:commandButton id="btDownload" ajax="false" value="Download" icon="ui-icon-document" >
<p:fileDownload value="#{myBean.downloadMethod()}" />
</p:commandButton>
</h:form>
The scope "view" on spring doesn´t exist... So you created your own, right? Just to check...
I had that kind of problem once, and I think it was something to do with validation... the
immediate=true attribute solved my problem.
This is something to do with the scope of the page. Your problem is due to partial rendering of page. Initially when you load the page it is not getting loaded fully and because of that the button is not part of that particular view when you try to click on the button for the first time. Try to make you view proper or explicitly render the page from the backing bean before displaying the page