I'm making page using Primefaces with form with ability to ajax-upload image and preview it before submitting whole form.
To achieve this I made dialog outside main form:
<p:dialog id="imageDlg" header="Load Image" modal="true"
widgetVar="imageUploadWidget">
<h:form id="imageForm" enctype="multipart/form-data">
<p:fileUpload mode="advanced" auto="true" sizeLimit="9999999"
allowTypes="/(\.|\/)(gif|jpe?g|png)$/"
fileUploadListener="#{pageBean.imageUploadHandler}">
</p:fileUpload>
</h:form>
</p:dialog>
Inside main form there is p:graphicImage
component to display just uploaded image and button to show dialog. Page is backed by view scoped bean (PageBean
), but to pass StreamedContent
to p:graphicImage
value bean should be session or application scoped (because method called multiply times). So I made second application scoped bean (ImageBean
) only for this purpose.
<p:graphicImage value="#{imageBean.imageStreamedContent()}"/>
<p:commandButton value="Choose image" type="button"
onclick="imageUploadWidget.show();"/>
Code of ImageBean
:
@ApplicationScoped
@ManagedBean
public class ImagesBean implements Serializable {
private byte[] image;
//getter & setter
public StreamedContent imageStreamedContent() {
FacesContext context = FacesContext.getCurrentInstance();
if (context.getCurrentPhaseId() == PhaseId.RENDER_RESPONSE) {
return new DefaultStreamedContent();
} else {
return new DefaultStreamedContent(new ByteArrayInputStream(getImage()));
}
}
}
The next part is fileUploadListener
. Idea is simple — set corresponding fields of PageBean
(to save it later on form submit) of ImageBean
(to show it after partial refresh) and update part of main form:
@ManagedBean
@ViewScoped
public class PageBean implements Serializable {
@ManagedProperty(value="#{imageBean}")
ImagesBean imagesBean;
...
public void imageUploadHandler(FileUploadEvent event) {
getImagesBean().setImage(event.getFile().getContents());
RequestContext.getCurrentInstance().update("form:tabPanel1");
}
Here comes strange thing. Inside setImage()
method everything is OK - field is set, getter works fine. But then page refresh, imageBean.getImage()
inside imageBean.imageStreamedContent()
returns null.
More accurate — it returns old value, as if setter was never called or was called on another instance of bean. I checked it on another String
field: initialized it in ImageBean
constructor, in handler invoked setter with another value and refreshed part of main form. Same thing: old value from constructor.
I think, that I'm missing something about bean life cycle or scope specific. Or maybe there is less complicated way to implement this task?