views:

110

answers:

2

I will try to be as brief as possible, please stay with me here

"A.jsf" -> managed bean : bean "#{bean.list}": will take us to B.jsf

        <p:growl id="msgs" showDetail="true"/>
        <h:form id="myform1" enctype="multipart/form-data">
            <p:panel header="Upload" style="font-size: 11px;">
                <h:panelGrid columns="2" cellpadding="10">
                    <h:outputLabel value="Drawing:" />
                    <p:fileUpload fileUploadListener="#{bean.handleFileUpload}" update="msgs" allowTypes="*.*;"/>                        
                </h:panelGrid>
                <p:commandButton ajax="false" immediate="true" id="back" value="Back" action="#{bean.list}"/>
                <p:commandButton ajax="false" id="persist" value="Persist" action="#{bean.handleRevision}" />
            </p:panel>
        </h:form>

Then the handleFileUpload()

        if(!upload){
            FacesMessage msg = new FacesMessage(FacesMessage.SEVERITY_ERROR, "Error", "You do not have permission to upload.");
            FacesContext.getCurrentInstance().addMessage(null, msg);
        }
        ...

"B.jsf" -> managed bean: bean2

 ...
 <p:growl id="msgs" showDetail="true"/>
 ...

When I click upload, it give me a growl error message "You do not have permission to upload.", which is good. But then when I click "Back", which will take me to B.jsf, I see the growl message "You do not have permission to upload." again. What seem to be happening is as I click the "Back", I send other form request to upload, which then generated the same error message, which then being displayed at B.jsf. Is there a way to fix this, beside putting the "Back" button into an empty form, because now I have two buttons standing on top of each others, instead of side by side. I try to do this:

FacesContext.getCurrentInstance().addMessage("tom", msg);

hoping that it would send to component with id="tom", so then the growl with id=msgs, would not get load, but no luck. I try to turn the upload flag on when I click the Back button, but the web form get requested before the method that handle the back navigation get called.

It is not as brief as I want it to be, therefore I want apologize for it :D

+1  A: 

Actually, putting the button in a different form sounds like an excellent solution. The reason the buttons don't align any more is that the new starting <form> element starts on its own line. You should be able to prevent this by adding form { display: inline; } to your CSS file.

That said, if you have some leftover error messages that you want to get rid of, you can do this in the initializing method of your backing bean (if you have one). The following works peachily:

public void clearErrorMessages() {
    //it may get messy to debug why messages are swallowed
    logger.debug("clearing messages, coming from " + new Exception().getStackTrace()[1]);

    Iterator iter = FacesContext.getCurrentInstance().getMessages();
    while (iter.hasNext()) {
        FacesMessage msg = (FacesMessage) iter.next();
        logger.debug("clearing message: " + msg.getDetail());
        iter.remove();
    }
}

The disadvantage here is that any errors that occur between submitting the form and initializing the backing bean of the target page are also swallowed.

László van den Hoek
thank you. I try this `<h:form style="margin:0;">Submit Button </h:form> <h:form> Back Button </h:form>`, I still have two standing one on top of each other. The method `clearErrorMessages()`, you said put it into initializing method of the target managed bean, well my target managed bean have `SessionScoped`, so the constructor will be called only one time when the application first load, unless there are some kind of annotations to detect when the page reload.
Harry Pham
+5  A: 

beside putting the "Back" button into an empty form, because now I have two buttons standing on top of each others

The HTML <form> is by default a block element. HTML block elements are by default been placed in a new line. You actually want to make it an inline element. You can do this using display: inline; in CSS.

Back to the actual problem, it however surprises me that the fileUploadListener method is called in spite of the immediate="true" in the p:commandButton. I tried to reproduce this and I can confirm this. But I wouldn't expect it to happen. Normally the immediate="true" on a button is the solution to skip submitting of the "whole" form (at least, skip the UIInput components without this attribute). Further investigation learnt me that the p:fileUpload isn't an UIInput component at all and that the listener is fired during apply request values phase instead of validations or update model values phase. So this behaviour is fully predictable, but imo still an oversight in the design.

Since the p:fileUpload requires ajax="false" on the p:commandButton component, you can on the other hand also just remove it from the back button so that it fires an ajaxical request and hereby skips the fileUploadListener being called.

BalusC
Taking out `ajax="false"` on the `p:commandButton` of the `Back` button does prevent `fileUploadListener` from being called, however also prevent `navigation flow`. As a result, `Back` button take me no where, however, `display:inline` works great, thank you so much for spend time on it, BalusC
Harry Pham
You're welcome.
BalusC