Sarpy Sarpy - 4 months ago 19
Ajax Question

Conditionally provide either file download or show export validation error message

I've been working on CRUD application, and I need to export data from database to csv file.
In order to export, I had to disable ajax, in a manner shown in following code:

<p:commandButton value="Export" ajax="false" action="myController.export"/>


In the method invoked, I create the file and download it via OmniFaces utility method:

Faces.sendFile(file, true);


Using the same method, I check if there actually is any data, and if there isn't any data, warning dialog is shown:

RequestContext.getCurrentInstance().showMessageInDialog(new FacesMessage(FacesMessage.SEVERITY_WARN, "Warning!", "No available data for export."));


Now, while all of this does work as intended, the problem is that because ajax is disabled, dialog cannot be dynamically shown, and page is reloaded. If ajax is enabled, dialog is shown dynamically, but file download doesn't start.

I've been trying to work around this issue, by using Monitor download, or by force clicking second button, but so far I haven't made any progress on the matter.

Is there any generally acceptable way of solving issues like this one?

Answer

Is there any generally acceptable way of solving issues like this one?

You basically want to fire an ajax request first and in its oncomplete check if it's successful, and then trigger a synchronous request to download the file (note that you can't download files with ajax). You could make use of FacesContext#validationFailed() (or OmniFaces Faces.validationFailed()) to mark the validation fail state which is available via args object which PrimeFaces injects in the oncomplete function context (note that ajax related attributes such as oncomplete don't work when ajax is disabled).

Something like this:

<p:commandButton 
    value="Export" 
    action="#{bean.export}" 
    oncomplete="if (args &amp;&amp; !args.validationFailed) PF('download').jq.click()" />
<p:commandButton 
    widgetVar="download" 
    styleClass="ui-helper-hidden" 
    action="#{bean.download}" ajax="false" />
public void export() {
    // Prepare file locally.

    if (fail) {
        // Show message your way and then set validation failed as below.
        Faces.validationFailed();
    }
}

public void download() throws IOException {
    Faces.sendFile(file, true);

    // Delete local file afterwards?
}

Note that a hidden <p:commandButton> is being used instead of <p:remoteCommand> as the latter doesn't support ajax="false".

Comments