views:

183

answers:

2

I have a commandButton that will invoke a function to download a file (standard stuffs like InputStream, BufferedOutputStream ...) After download success, at the end of the function, I change some values of the current object and persist it into database. All of these work correctly. Now when file is done downloading, the content of the page is not updated. I have to hit refresh for me to see updated content. Please help. Below are the basic structure of my code

document: Managed Bean
getDrawings(): method return a list of Drawing (entity class)
CheckedOutBy: attribute of Entity Drawing

<p:dataTable id="drawing_table" value="#{document.drawings}" var="item" >                            
    <p:column>
        <f:facet name="header">
              <h:outputText value="CheckedOutBy"/>
        </f:facet>
        <h:outputText value="#{item.checkedOutBy}"/>
        ...
</p:dataTable>
<p:commandButton ajax="false" action="#{document.Download}" value="Download" />

Inside my Managed Bean

public void Download(){
    Drawing drawing = getCurrentDrawing();
    //Download drawing
    drawing.setCheckedOutBy("Some Text");
    sBean.merge(drawing);  //Update "Some Text" into CheckedOutBy field
}
A: 

You could use the update attribute of the p:commandButton component to re-render the area that you intend to refresh after download, in this case your "drawing_table".

<p:commandButton update="drawing_table" action="#{document.Download}" value="Download" />
StudiousJoseph
I did try that, but it did not work. Not sure why
Harry Pham
It's because of `ajax="false"` (which is mandatory to get the file to download).
BalusC
ahhhh that why. Thanks BalusC!!! It's good to know that
Harry Pham
+1  A: 

You'd basically like to let the client fire two requests. One to retrieve the download and other to refresh the new page. They cannot be done in a single HTTP request. Since the download needs to be taken place synchronously and there's no way to hook on complete of the download from the client side on, there are no clean JSF/JS/Ajax ways to update a component on complete of the download.

Your best JSF-bet with help of PrimeFaces is <p:poll>

<h:outputText id="checkedOutBy" value="#{item.checkedOutBy}"/>
...
<p:poll id="poll" interval="5" update="checkedOutBy" />

or <p:push>

<p:push onpublish="javaScriptFunctionWhichUpdatesCheckedOutBy" />  

Polling is easy, but I can imagine that it adds unnecessary overhead. You cannot start it using standard JSF/PrimeFaces components when the synchronous download starts. But you can stop it to let it do a self-check on the rendered attribute. Pushing is technically the best solution, but tougher to get started with. PrimeFaces explains its use however nicely in chapter 6 of the User Guide.

BalusC
thank you for your input. I am reading the chapter now. I will get back to you if I have more question. Thanks for edit my post, switch from `h:commandButton` to `p:commandButton`. I originally have it as `p:commandButton`, but I was worry that many people would not understand it, since `primefaces` tag only have `38` rating.
Harry Pham
This isn't a rating, this is just the amount of tagged questions as far. As long as you tag `jsf` along it, it'll be spotted by the right people ;)
BalusC
I am still a bit vague. So does my `p:commmandButton` become this `<p:commandButton ajax="false" action="#{document.Download}" actionListener=”#{document.update}” value="Download" />`. My entity Drawing have a boolean `checked` attribute which essentially tell me which `drawing` the user select. So it could be multiples drawings select to be downloaded. Therefore, my `update` method on the server, I dont have a clear idea of what to `push` down to the browser. Do you think I should put down the entire column of `checkedOutBy`, or somehow figure out which one need to be updated, and push them
Harry Pham
Send a delimited/formatted string which you can process further in JS code. JSON format may be highly suitable here.
BalusC
Currently, I dont think push is supported in Glassfish, according to people from primefaces forum. I guess poll is my only option. Do u mind elaborate what u said earlier: `You cannot start it using standard JSF/PrimeFaces components when the synchronous download starts. But you can stop it to let it do a self-check on the rendered attribute.`
Harry Pham
Something like `<p:poll id="poll" interval="5" update="checkedOutBy poll" rendered="#{!downloadFinished}" />`
BalusC
I see once you done downloading, u set the boolean `downloadFinished`. You cannot start poll when the synchronous download start because the download use up the only one HTTP request
Harry Pham
I did not like `polling` too much, since it keep refresh the table when it does not need too. I redesign, so that it took me to a confirm page, so when the user done downloading, they click `Back` to return back to the list, at which point, a new Http request is created and refresh the page. I marked this your post as solution, since it `push` and `poll` actually work well, just not for me :D
Harry Pham
You're welcome.
BalusC