So basically, I have a fileUploader that I want to do multiple files at a time. When I click upload with 2 or more files, it runs the event handler once, and then stops, not running it again for the rest of the files, even though it shows them in queue on the page.
<h:panelGroup>
<h:panelGrid columns="3" >
<h:outputText value="Attach Files:"/>
<p:fileUpload allowTypes="/(\.|\/)(doc|docx|xls|xlsx|pdf)$/" mode="advanced" multiple="true" sizeLimit="30000000" auto="true" fileUploadListener="#{requestPart.handleFileUpload}" update="messages"/>
<p:messages id="mgs" showDetail="true"/>
</h:panelGrid>
</h:panelGroup>
My event handler code is as follows
private List<UploadedFile> uploadedFileList = new ArrayList<UploadedFile>();
public void handleFileUpload(FileUploadEvent event) throws NotSupportedException, SystemException, SQLException
{
System.out.println("Uploading Request Part files....");
UploadedFile file = event.getFile();
uploadedFileList.add(file);
FacesMessage msg = new FacesMessage("File attached successfully.", file.getFileName() + " is uploaded.");
FacesContext.getCurrentInstance().addMessage(null, msg);
}
Could anyone point me in the write direction? As far as I know, the event is just one file at a time and never a list?
Which version of PF?
I had similar problem with PF 5.0.
Try with this:
public static synchronized void addToList{
uploadedFileList.add(file);
}
My solution is:
sequential="true" add in your fileUpload and your bean
private List<UploadedFile> archImagen;
public void handleFileUpload(FileUploadEvent event) {
archImagen.add( event.getFile());
}
Related
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;
}
}
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.
I know my question is quite basic but I couldn't find anything on SO or Google regarding this.
I am using PrimeFaces and their p:fileUpload component. It is working fine, files are being uploaded. The problem is, after these files are uploaded, I need to show user how many files are uploaded, and not using JavaScript. I need this number in my Backing Bean.
There is one oncomplete attribute but that is for client side callback (which again is JavaScript).
Following is my humble code :)
<p:fileUpload required="true" requiredMessage="No files selected."
mode="advanced"
multiple="true"
dragDropSupport="true"
allowTypes="/(\.|\/)(gif|jpe?g|png)$/"
update="growlMessage"
fileUploadListener="#{mainForm.fileUploadListener}">
</p:fileUpload>
And here is backing bean:
#ManagedBean
#SessionScoped
public class MainForm {
private int totalImageFiles;
public MainForm() {
this.totalImageFiles = 0;
}
public void fileUploadListener(FileUploadEvent event) {
UploadedFile uploadedFile = event.getFile();
ReaderWriter.ReadWrite(uploadedFile, yourName, yourHomeAddress, totalImageFiles);
totalImageFiles++;
}
}
totalImageFiles is the number that I want to show user. It has the correct values but I don't know how to send another request to retrieve this number.
Just reference it in some output component and ajax-update it.
<p:fileUpload ... update="growlMessage totalImageFiles" />
<h:outputText id="totalImageFiles" value="#{mainForm.totalImageFiles}" />
I have the fileLimit seted to 1.
I want that when the user choose the first file, the choose button get disabled.
I resolved putting a disabled atribut in fileUpload liked with a boolean variable in my bean.
When the file finish to upload, the variable change his values to true and I update the fileUpload componnt, then the component get disabled.
Thank you guys to the help.
Try this.
xhtml
<p:fileUpload fileUploadListener="#{fileUploadView.handleFileUpload}"
mode="advanced"
dragDropSupport="false"
update="messages,#this"
sizeLimit="100000"
fileLimit="1"
allowTypes="/(\.|\/)(gif|jpe?g|png)$/"
disabled="#{fileUploadView.fileUploadCount >= 1}"/>
<p:growl id="messages" showDetail="true" />
managedbean
#ManagedBean
public class FileUploadView {
private int fileUploadCount;
public int getFileUploadCount() {
return fileUploadCount;
}
public void setFileUploadCount(int fileUploadCount) {
this.fileUploadCount = fileUploadCount;
}
public void handleFileUpload(FileUploadEvent event) {
FacesMessage msg = new FacesMessage("Succesful", event.getFile().getFileName() + " is uploaded.");
FacesContext.getCurrentInstance().addMessage(null, msg);
fileUploadCount = fileUploadCount + 1;
}
}
This proposed is easy to change file limit. When you want to change fileLimit to 2 you just change
fileLimit="2" and disabled="#{fileUploadView.fileUploadCount >= 2}" without modify managedbean.
I'm very new to PrimeFaces components. I have a FileUpload (multiple files uploaded) and I want to know if there's a way to know how many files are in the upload component before uploading them.
What I need is to upload 1 to 6 files and just after the 6th is uploaded process the all the files.
Any idea on how can I achieve this is very welcome.
Cheers
UPDATE
Already tried with oncomplete but it does not help me 'cause this event is executed every time a file is uploaded not 'till all files are.
Ok, this is pretty old thread but I've found straitforward way to determine the number of files been uploaded.
p:fileUpload widget has an array with meta-info about selected files. By passing the length of this array to your bean you will obtain the total number of files.
There is a problem though: p:fileUpload doesn't submit the surrounding form, so I had to put invisible button along with the h:inputHidden to pass the number of files from JavaScript to ManagedBean:
<h:form id="importDlgForm">
<p:fileUpload id="importFile" widgetVar="importFile" fileUploadListener="#{importDialogView.importFile}"
mode="advanced" multiple="true"
onstart="$('#importDlgForm\\:file_number_input').val(PF('importFile').files.length);
$('#importDlgForm\\:submit_btn').click();"/>
<h:inputHidden id="file_number_input" value="#{importDialogView.importFileNumber}"/>
<p:commandButton id="submit_btn" style="display: none"/>
</h:form>
I also had to use AtomicInteger in order to track processed files, as p:fileUpload uses multiple threads to upload files by default.
private final AtomicInteger atomicImportFileNumber = new AtomicInteger();
private Integer importFileNumber;
public Integer getImportFileNumber() {
return importFileNumber;
}
public void setImportFileNumber(Integer importFileNumber) {
this.importFileNumber = importFileNumber;
atomicImportFileNumber.set(importFileNumber);
}
public void importFile(FileUploadEvent event) {
// common file upload stuff
if (atomicImportFileNumber.decrementAndGet() == 0) {
// part to execute only when all files have been uploaded
}
}
If you want to upload all the files, all 6 of them at once or only 1 at a time, and then call a processing message, you have to create a variable or better a list where you insert the name of each file, or even the file objects and when the ArrayList size reach 6 you call a processing method. Simple as that!
private ArrayList<UploadedFile> listWithUploadedFile = new ArrayList<UploadedFile>();
public void uploadMethod(){
//upload file, save input stream and any other thing you want
listWithUploadedFile.add(file);
if(listWithUploadedFile.size==6){
myProcessUploadedFilesMethod();
}
}
I've modified the Aleksandr's answer to simplify the onstart command, by the price of more complicated Java part.
</div>
<p:fileUpload widgetVar="importFile" listener="#{fileUploadView.handleFileUpload}" dragDropSupport="true" mode="advanced" multiple="true"
onstart="rc([{name:'size', value:PF('importFile').files.length}])"/>
<p:remoteCommand name="rc" update="messages" actionListener="#{fileUploadView.setSize}" />
</div>
and
#Named
#ViewScoped
public class FileUploadView {
private AtomicInteger size = new AtomicInteger();
private List<UploadedFile> files = new ArrayList<>();
public void setSize(ActionEvent e) {
String length = e.getFacesContext().getExternalContext().getRequestParameterMap().get("size");
if(length != null) {
size.set(Integer.parseInt(length));
}
}
public void handleFileUpload(FileUploadEvent event) {
files.add(event.getFile());
if(size.decrementAndGet() == 0) {
FacesMessage msg = new FacesMessage("Successful", files.size() + " uploaded");
FacesContext.getCurrentInstance().addMessage(null, msg);
files.clear();
}
}
}
I'm using PrimeFaces for a new project and it's quite an impressive set of components.
Anyway, I have problem with "real world" use of filedownload component.
In my page I have a datalist that shows the attachments related to a particular document, and I want provide a link to directly download that file inside the datalist item.
Here's my xhtml code:
<p:dataList id="ListaAllegati" value="#{documentBean.documento.allegati}" type="definition" var="attach" style="border: none" ">
<f:facet name="description">
<h:outputText value="#{attach.name}" />
<p:commandLink ajax="false" title="Download" action="#{documentBean.selectAttach}>
<h:graphicImage style="margin-left: 10px; border: none" value="./images/article.png" height="24" width="24" ></h:graphicImage>
<p:fileDownload value="#{documentBean.downloadFile}"/>
<f:setPropertyActionListener target="#{documentBean.selectedAttach}" value="#{attach}" />
</p:commandLink>
</f:facet>
</p:dataList>
and the relative java bean (request scoped):
private StreamedContent downloadFile;
public StreamedContent getDownloadFile() {
log.info("getter dell'allegato invocato");
InputStream stream = null;
byte[] rawFile = null;
if (selectedAttach == null) {
log.warn("Nessun allegato passato");
return null;
} else {
try {
log.info("Recupero del file " + selectedAttach.getGuid());
rawFile = attachManager.retrieveFile(selectedAttach.getGuid());
} catch (Exception e) {
String msg = "Errore durante il recupero del file";
log.error(msg, e);
FacesMessage fmsg = new FacesMessage(msg, "");
FacesContext.getCurrentInstance().addMessage(null, fmsg);
}
stream = new ByteArrayInputStream(rawFile);
DefaultStreamedContent file = new DefaultStreamedContent(stream,
selectedAttach.getMimeType(), selectedAttach.getName());
return file;
}
}
public void selectAttach() {
log.info("commandLink action invocata");
}
private Allegato selectedAttach;
public Allegato getSelectedAttach() {
return selectedAttach;
}
public void setSelectedAttach(Allegato selectedAttach) {
log.info("Allegato selezionato");
if (selectedAttach==null) log.warn("L'allegato passato รจ nullo");
this.selectedAttach = selectedAttach;
}
So, couple of question:
Am I doing the right thing trying to pass the selected attachment that way? Otherwise, how can I pass a parameter to tell the bean wich attachment has been clicked?
Why the first time I click the command link, nothing happen? It make a roundtrip with server, but nothing happens. Second time, it gives me an exception.
Why documentBean.selectAttach is never called and the documentBean.selectedAttach property is never set (neither the second time)?
Thanks to anyone for any hint
How to get the row object from the datatable is answered in this question:
How can I pass selected row to commandLink inside dataTable?
This answers basically all the three questions.
As to the exception in the second click, that's likely because you didn't return from the catch block when an exception is been thrown in your getDownloadFile() method. You're continuing the remnant of the code flow while the rawFile is still null. Fix it accordingly as well. Add a return null to the end of catch or something. Better yet, you should be posting the entire stacktrace in the question as you don't seem to be able to understand it. It basically already contains the answer :)
Primefaces has its own dedicated servlet for file download and upload components that handle all of this asynchronously.
Try doing something like what I have in my code
<p:commandLink ajax="false" actionListener="#{managedBean.downloadAction(object)}">
<span class="ui-icon icoFolderGo" style="padding-right: 1.5em;" />
<p:fileDownload value="#{managedBean.downloadContentProperty}" />
</p:commandLink>
And in the managed bean,
public void downloadAction(Object object) {
try {
InputStream stream = // get input stream from argument
this.setDownloadContentProperty(new DefaultStreamedContent(stream, "application/pdf", "filename.pdf");
} catch (Exception e) {
log.error(e);
}
}
public void setDownloadContentProperty(StreamedContent downloadContentProperty) {
this.downloadContentProperty = downloadContentProperty;
}
public StreamedContent getDownloadContentProperty() {
return downloadContentProperty;
}