2

I'm using PrimeFaces' simple fileUpload and a custom submit button, something like this:

<h:form enctype="multipart/form-data">

    <p:fileUpload value="#{fileController.file}"
                  mode="simple"
                  skinSimple="true"
                  label="choose file"/>

    <p:commandButton value="upload"
                     ajax="false"
                     label="upload"
                     icon="fa fa-upload"
                     actionListener="#{fileController.upload}"/>
</h:form>

In the backing bean, file is a property of type UploadedFile.

Now I want to disable the upload button if no file is selected yet, but I fail to get the Information whether the user has selected a file or not the file property remains null until the upload button is clicked). I tried the valueChangeListener on the <p:fileUpload> component, but the event is only fired when I click the upload button (but then it's too late)

Anyone has a suggestion?

Tiny
  • 27,221
  • 105
  • 339
  • 599
Raphael Roth
  • 26,751
  • 15
  • 88
  • 145

1 Answers1

8

You ultimately need a hook on the HTML DOM change event of <input type="file">. Without ajax (via <p:ajax>) that gets tricky with <p:fileUpload mode="simple"> for 2 reasons:

  • It doesn't support onchange attribute. It might be worth an enhancement request to PF guys. Fortunately, since JSF 2.2 you can specify passthrough attributes.
  • skinSimple="true" generates a <span><span><input /></span></span> and the passthrough attribute would render onchange on all those elements. You need an additional check if this is the <input> element.

All in all, here's how it could be done:

<html ... xmlns:a="http://xmlns.jcp.org/jsf/passthrough">
...
<h:form enctype="multipart/form-data">
    <p:fileUpload label="choose file" mode="simple" skinSimple="true"
        value="#{bean.file}"
        a:onchange="if (tagName == 'INPUT') { if (!!value) PF('button').enable(); else PF('button').disable(); }" />

    <p:commandButton widgetVar="button" value="upload" 
        action="#{bean.upload}" ajax="false"
        disabled="#{facesContext.renderResponse or not facesContext.postback}" />
</h:form>

The condition in the disabled attribute of the button makes sure that it's only disabled during render response phase and an initial GET request. Otherwise JSF would refuse to queue the action event as per point 5 of commandButton/commandLink/ajax action/listener method not invoked or input value not updated.

The button is tied to the document as widgetVar so that JS could enable/disable it via its enable() and disable() functions.

Community
  • 1
  • 1
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • unfortunately it's not working as expected, i get an error: Error Parsing XXX.xhtml: Error Traced[line: XXX] The prefix "a" for attribute "a:onchange" associated with an element type "p:fileUpload" is not bound. Using primefaces 5.2 by the way and jsf 2.2.12 – Raphael Roth Oct 09 '15 at 07:01
  • So you didn't click the "passthrough attributes" link to learn about it? I'll update the answer. – BalusC Oct 09 '15 at 07:07
  • i clicked it, but didn't read it carefully enough it seems. Thanks again for this great answer, you seem to know everything about jsf.. respect – Raphael Roth Oct 09 '15 at 07:12
  • You're welcome. JSF is much easier if you know a bit of HTTP/HTML/CSS/JS (after all, that's what JSF is consuming and producing under the covers). – BalusC Oct 09 '15 at 07:14