1

I have an application with a file uploader and I would like to display some information from the selected files before the user uploads them.

E.g. The user selects a file to upload, the application, client side, then grabs that file and reads some information from it to display to the view. Then if it is what the user expects to see they can hit upload.

Is there a way to call a method in the backing bean when a file is selected and pass it that file, or does PrimeFaces not let this happen?

index.xhtml

<h:form id="uploadform" prependId="false" enctype="multipart/form-data">
    <p:outputPanel id="container">
        <center>
            <p:fileUpload fileUploadListener="#{uploadBean.handleFileUpload}" mode="advanced"
                    dragDropSupport="false" allowTypes="/(\.|\/)(csv|xlsx)$/" update="messages"/>

            <p:growl id="messages" showDetail="true" />

        </center>
    </p:outputPanel>                
</h:form>

UploadBean.java

import org.apache.poi.util.IOUtils;
import org.primefaces.event.FileUploadEvent;
import org.primefaces.model.UploadedFile;

@ViewScoped
@ManagedBean(name = "uploadBean")
public class NetezzaUploadBean implements java.io.Serializable {

    private static final long serialVersionUID = 1L;

    private UploadedFile file = null;

    @PostConstruct
    public void init() {
    }

    public void getFileBeforeSubmit() {
        //Where I want to do some work with the file    
    }

    public void handleFileUpload(FileUploadEvent event){
        FacesMessage message = new FacesMessage("Succesful", event.getFile().getFileName() + " is uploaded.");
        FacesContext.getCurrentInstance().addMessage(null, message);
    }

    public UploadedFile getFile() {
        return file;
    }

    public void setFile(UploadedFile uploadedFile) {
        this.file = uploadedFile;
    }
}
Kukeltje
  • 12,223
  • 4
  • 24
  • 47
Ras
  • 67
  • 3
  • 12
  • What does your `public void handleFileUpload(FileUploadEvent event)` do? Looks like you have a handle to a file there. – Kukeltje Sep 19 '18 at 17:15
  • Possible duplicate of [How to use PrimeFaces p:fileUpload? Listener method is never invoked or UploadedFile is null / throws an error / not usable](https://stackoverflow.com/questions/8875818/how-to-use-primefaces-pfileupload-listener-method-is-never-invoked-or-uploaded) – Kukeltje Sep 19 '18 at 17:18
  • Ah you mean **before** uploading... What do you want to show? – Kukeltje Sep 19 '18 at 17:34
  • @Kukeltje Yes exactly. I can get that handleFileUpload method to call and work fine. I want to be able to show an image preview of a specific part of the document. I have some code already to create the image I need from the document to display. – Ras Sep 19 '18 at 17:40
  • And what info do you want to show? Only having the filename makes it next to impossible to provide reliable feedback ('whats in a name') – Kukeltje Sep 19 '18 at 17:41
  • @Kukeltje I want to generate an image preview of a piece of the file to display to the user before submission. I can already create the image I need, I just don't know how to pass the file to my function at the right time to do so. – Ras Sep 19 '18 at 17:44
  • @Kukeltje wait, so the fileUpload only holds the file name before it is uploaded? Does that mean there is no way for me to get the actual contents of the file for what I am trying to do? – Ras Sep 19 '18 at 17:49
  • No idea, that is why I asked what you wanted to show... I know PrimeFaces can do an image preview, but if you want to show, so either the browser plays a role or you can actually retrieve the file in a different way. Anyway, the source is with you... it IS open... https://github.com/primefaces/primefaces/blob/master/src/main/resources/META-INF/resources/primefaces/fileupload/2-fileupload.js#L181 and https://scotch.io/tutorials/use-the-html5-file-api-to-work-with-files-locally-in-the-browser – Kukeltje Sep 19 '18 at 18:28
  • @Kukeltje Thank you for your help. I will post back if I ever manage to solve my problem. – Ras Sep 19 '18 at 18:44
  • You can easily override the `addFileToRow` and e.g. after the preview call your own function. But there even seems to be a non-documented [`onAdd`](https://github.com/primefaces/primefaces/blob/master/src/main/resources/META-INF/resources/primefaces/fileupload/2-fileupload.js#L97). Not sure how to use it though.... – Kukeltje Sep 19 '18 at 19:27
  • Maybe by adding a `binding="..."` and set it from there with the value of your javascript function – Kukeltje Sep 19 '18 at 19:35
  • Check the answer... I tested this in the showcase via the browser developer console and it works! – Kukeltje Sep 19 '18 at 20:43
  • Off-topic: using prependId=false should be prevented at all times. https://stackoverflow.com/questions/7415230/uiform-with-prependid-false-breaks-fajax-render – Kukeltje Sep 19 '18 at 22:07
  • Any feedback? I put a fair amount of effort in helping out. Would be kind of nice if you responded in any way. I've seen you being online yesterday... – Kukeltje Sep 26 '18 at 05:56
  • @Kukeltje Not yet. I have had other things take precedence. – Ras Sep 26 '18 at 19:51
  • Please next time post a short message like you now did... – Kukeltje Sep 26 '18 at 19:55

1 Answers1

3

PrimeFaces p:fileUpload seems to have a great undocumented feature where you can make use of the native file input 'onAdd' event (or sort of). I found this in the source (which is open ;-)) of the 2-fileUpload.js file

if($this.cfg.onAdd) {
    $this.cfg.onAdd.call($this, file, function(processedFile) {
       file = processedFile;
       data.files[0] = processedFile;
       this.addFileToRow(file, data);
    });
}

The cfg property from $this can be accessed via

PF('myWidgetId').cfg

And if you declare a function upfront like

function myOnAddHandler(file) {
    console.log(file);
}

And add it to the widget with

PF('myWidgetId').cfg.myOnAddHandler;

You can select a file and before uploading see it logged in the console

File { name: "myImage.PNG", lastModified: 1533756086560, webkitRelativePath: "", size: 38344, type: "image/png" }

You can then extend this to use the HTML5 File API and read it

function myOnAddHandler(file) {
    var reader = new FileReader(); 
    reader.onload = function(readerEvt) { 
        var binaryString = readerEvt.target.result;
        console.log(btoa(binaryString));
    };
    reader.readAsBinaryString(file);
}

PrimeFaces itself uses this sort of too in the related addFileToRow to show the preview

After looking in more of the java code of PrimeFaces, it might even be that instead of doing PF('myWidgetId').cfg.myOnAddHandler;, you could do <p:fileUpload onAdd="myOnAddHandler" .... /> I unfortunately do not have the time to test this right now but it might work.

Kukeltje
  • 12,223
  • 4
  • 24
  • 47
  • So I was able to look into what you typed up and the onAdd seemed to be exactly what I was looking for to get the file before the upload event. I tried your theory about using `` but it didn't seem to trigger, just in case you were curious about that. However thank you for your time. Sorry it took so long to get back to you. – Ras Sep 26 '18 at 20:39
  • Cheers... Great it works. If it realy helped, upvoting is allowed too ;-) – Kukeltje Sep 26 '18 at 21:26
  • Yeah I would've before but my rep was too low. – Ras Sep 27 '18 at 17:23
  • Oh? you can 't upvote the answers on your own questions if you have to little rep? Never knew that.... – Kukeltje Sep 27 '18 at 17:25
  • No under 15 it always said that the upvote would not be recorded. Not sure if that always just meant not recorded publicly but still attributed to the user or just not recorded all together. – Ras Sep 27 '18 at 17:29