Showing posts with label AJAX. Show all posts
Showing posts with label AJAX. Show all posts

Monday, 27 July 2015

Temporarily disable or conditional executing of PrimeFaces AJAX calls

Introduction

In JSF 2.0, the AJAX functionality is standardised in the specification and can be used in a consistent way between JSF implementations and component libraries like PrimeFaces.
With the addition of new functionality, new usage patterns become a habit. But new usages also brings more advanced scenarios with their own issues.

The situation I want to discuss today, is where you have the need for some partial screen update with AJAX but which you don't want in all situations. The conditional aspect which I referred to in the title of the text.

Problem description


Suppose you have the following screen area:


It contains the following elements from left to right
* A field to enter an existing code. When the end user leaves the field, the code is looked up.
* A second, read only field or label, where the description of the code is placed when it is an existing one.
* A button, which is only available when the first field doesn't contain an existing code and lets you add a new one.

Within the JSF page, the structure looks something like this.

<h:panelGroup id="codeArea">
    Code :
    <p:inputText value="#{codeBean.code}" id="code">
        <p:ajax event="blur" listener="#{codeBean.onBlurCode}" update="codeArea"/>
    </p:inputText>
    <p:inputText value="#{codeBean.codeDescription}" disabled="true" placeholder="description"/>
    <p:commandButton icon="fa fa-plus-circle" actionListener="#{codeBean.addCode}" update="codeArea" disabled="#{empty codeBean.description}"/>
</h:panelGroup>

With the ajax tag within the input field, we can perform the partial screen update when we leave the input field. We need to update the complete group as the button needs to become disabled as we enter an existing code.

Conditional executing

This construct works perfectly when you tab out of the input field.  The blur event triggers the AJAX execution and the server side code checks if the code exists. Due to the partial screen update the button becomes disabled when the code doesn't exists or enabled when the code isn't found.

But there is a scenario which fails; when the focus is in the input field and we click on the command button.  You will found out that the click on the button is ignored.  

If we inspect what is happening in the network console of the browser; we see that there is an AJAX request to the server which corresponds to the blur event of the field.  But there is no request which corresponds to the click on the button.
This is because the blur event replaced the DOM element in the browser with another, for the end user identical component. So the click is on an element which no longer exist on the screen after the AJAX  completes.

So how can we solve this? Luckily PrimeFaces uses JQuery on the client side.  So when we could disable the onblur event execution in the case when we click on the button, we have a solution. And the good thing is that we can achieve this, quite easily.

The mousedown event is executed before the blur event. This is can bee seen by the following testing code. (thanks to mudassir)

So by adding the following code:

onmousedown="$(PrimeFaces.escapeClientId('frm:code')).off();"

We can remove all event handlers from the input field, and thus the click is executed.

Conclusion

Making the AJAX functionality can be easily achieved within PrimeFaces with the help of JQuery which is already available in the browser? In this text I showed you how you can disable the blur event in the case when you click a specific button but it will be active in other scenarios.



Sunday, 29 March 2015

Advanced File download with PrimeFaces

Introduction


When your Web application needs to send a file to the browser, the classic approach is using a web servlet to serve the contents.
PrimeFaces has a specific tag for downloading a file, so that you don't need a servlet. And with a small trick, you can even update the screen in the same action.

FileDownload component

The example with the servlet can be skipped, I guess. Everyone created already a servlet which is able to send content to the browser.
When you are working with JSF, and PrimeFaces, there is an alternative for the servlet approach.
PrimeFaces has the FileDownload component. It is an ActionListener, so you can use it on a commandButton to perform the download.

Let's have an example.
<p:commandButton value="Download" ajax="false">
    <p:fileDownload value="#{fileBean.file}"/>
</p:commandButton>

@ManagedBean(name = "fileBean")
@RequestScoped
public class FileDownloadController {

    public StreamedContent getFile() {
        InputStream stream = this.getClass().getResourceAsStream("/yourfile.txt");        return new DefaultStreamedContent(stream, "text/plain", "downloaded_file.txt");    }
    
}

The StreamedContent, already used by the graphicImage component, contains the data which is send to the browser. You can supply the constructor with an InputStream which has the actual contents.

This can be static file or a dynamically generated one. The PrimeFaces code is then responsible for reading from the InputStream and send it to the browser. Together with the required housekeeping like setting the mime type, http status and setting the JSF response as completed.

Advanced use case

Together with file download, there are use cases where you also need to update the screen which initiated the download.
Recently we had the use case where the end user can specify some options of the file he wants to download.  The options are presented in a dialog which should be preferably closed when the download is performed. Also the screen should be indicate the file download occurred.

Here the RemoteCommand is the solution to these cases.  The RemoteCommand allows to call some JSF bean methods and JSF lifecycle methods from JavaScript.

<p:commandButton value="Download2" ajax="false" onclick="pageRefresh();">
    <p:fileDownload value="#{fileBean.file}"/>
</p:commandButton>
<p:remoteCommand update="@all" name="pageRefresh"/>

When we click on the button, the onClick activates the javaScript version of the RemoteCommand and initiates a AJAX partial page refresh of the screen. On the other hand, the click on the button also initiates the ActionListener of the FileDownload component to perform the file download.

Since we where able to initiate 2 calls, we can perform 2 actions, the download and the screen update.

Conclusion

With the help of the FileDownload component it becomes easier to program the download of a static or dynamic file in JSF. You no longer need a servlet to perform these kind of actions.
With the help of the very broad useable RemoteCommand component, we can even initiate 2 actions.  The file download and some screen updates.