I would appreciate it if someone can give me some hints about progress bar and ajax back-end processing.
To clarify what I need following are details:
I have a command button to do some processing at the back-end.
I would like to show a progress bar that reach the 100% when the backing bean finishes processing back-end instructions.
I looked over many threads but no luck. Most of them did not show a concrete sample how to do that.
Below is a snippet of my code:
</h:panelGrid>
<p:commandButton id="btn" value="DoSomeAction"
styleClass="ui-priority-primary" update="panel"
onclick="PF('pbAjax').start();PF('startButton1').disable();"
widgetVar="startButton1"
actionListener="#{actionBean.DoSomeAction}" />
<p:progressBar widgetVar="pbAjax" ajax="true"
value="#{progressBean.progress}" labelTemplate="{value}%"
styleClass="animated">
<p:ajax event="complete" listener="#{progressBean.onComplete}"
update="growl" oncomplete="startButton2.enable()" />
</p:progressBar>
</p:panel>
This is the code for the Progress Brean:
#ManagedBean(name="progressBean")
public class ProgressBean implements Serializable {
private Integer progress;
public Integer getProgress() {
if(progress == null)
progress = 0;
else {
progress = progress + (int)(Math.random() * 35);
if(progress > 100)
progress = 100;
}
return progress;
}
public void setProgress(Integer progress) {
this.progress = progress;
}
public void onComplete() {
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, "Progress Completed", "Progress Completed"));
}
public void cancel() {
progress = null;
}
}
The result of this code is just an empty progress bar and nothing happen when I click on my button.
Thanks in advance.
It'll be easier if I simply walk you through my sample code since you have two beans and I don't know the interaction between them. You can use it to apply it to yours.
<p:commandButton>
<p:commandButton value="Start" type="button" onclick="pbAjax.start();startButton1.disable();" widgetVar="startButton1" />
Nothing impressive here. You have a commandButton with widgetVar="startButton1". When you click on it, onclick comes in and disables the commandButton. It also signals <p:progressBar> to start via pbAjax.start() (<p:progressBar> has widgetVar = "pbAjax.start()").
<p:progressBar>
<p:progressBar widgetVar="pbAjax" value="#{progressBean.progress}" ajax="true" labelTemplate="{value}%">
<p:ajax event="complete" listener="#{progressBean.onComplete}"
update="growl" oncomplete="startButton1.enable()"/>
</p:progressBar>
<p:progressBar> will simply keep calling #{progressBean.progress} to update the progress. When the progress reaches 100% <p:ajax> kicks in and calls #{progressBean.onComplete}. <p:commandButton> get re-enabled and <p:growl> gets updated. Notice how I'm not using PF(...). To be honest, I'm not sure if it makes a difference, I did not test.
Note
In your <p:progressBar> you have oncomplete="startButton2.enable(). It should be startButton1.enable() since your widgetVar value for your <p:commandButton> is startButton1.
Also, notice that I did not use styleClass="animated". With this, you'll just get the bland looking blue bar. If you want to use it then you need to take some extra steps. Looking at your code, it seems you're taking it straight from the PrimeFaces showcase so I'll also use their assets.
Using styleClass="animated"
First, you're going to create a folder called resources in your webapp folder (Web Pages for Netbeans). Then create a folder called css and add in a stylesheet called style.css. The directory structure will be like this: resources/css/style.css. In style.css you're going to have to define this rule. (Don't worry if this is confusing, I'll have the whole code below).
.animated .ui-progressbar-value {
background-image: url("#{resource['images/pbar-ani.gif']}");
}
Then you're going to create an images folder under resources and place the image
pbar-ani.gif in that folder (resources/images/pbar-ani.gif). Image below.
Make sure you have <h:outputStylesheet name='css/style.css' /> in <h:head> and add styleClass="animated" in <p:progressBar>.
Important!
If you are using PrimeFaces 3.5 like I am the image will just not display (including when you're not using styleClass). If you look closely at Firebug you will see the following error
Uncaught TypeError: Object #<Object> has no method 'easeInOutCirc'
One workaround I found for this is to simply use dummy <p:dialog>.
That's it.
You can get more information about the progressBar through the developer's guide.
In case you're wondering how I knew where to get the image you'll have to download the showcase. You can read this article to find out how to download the showcase.
In my opinion, when you really want to use the showcase code, it's better if you simply download the demo. Often time I'm either not seeing the complete picture or the code in the showcase has some mistakes
Anyway here's the sample code as promised. I'm using the same ProgressBean from the showcase (same as yours). Keep in mind that you will have to come up with the logic with how your object interacts with ProgressBean to update the progress bar.
Summary
<h:head>
<h:outputStylesheet name='css/style.css' />
</h:head>
<h:body>
<h:form >
<p:growl id="growl" />
<h3>Advanced Ajax ProgressBar</h3>
<p:commandButton value="Start" type="button" onclick="pbAjax.start();
startButton1.disable();" widgetVar="startButton1" />
<br /><br />
<p:progressBar widgetVar="pbAjax" value="#{progressBean.progress}" ajax="true" labelTemplate="{value}%" styleClass="animated">
<p:ajax event="complete" listener="#{progressBean.onComplete}"
update="growl" oncomplete="startButton1.enable()"/>
</p:progressBar>
<p:dialog></p:dialog><!-- For PrimeFaces 3.5 -->
</h:form>
</h:body>
and remember your directories
resources/css/style.css
resources/images/pbar-ani.gif
Related
I have a <p:datable> to display some products items. One of the item is a <p:graphicImage>. I would like to make this image clickable and display image in bigger in a popup when the image is clicked. Note that the images are stored in a database.
I've tried something like that:
<h:commandLink id="imageBtn"
action="#{imageBean.showImg(_product.id)}">
<p:graphicImage id="product_thumbnail" styleClass="thumbnail"
cache="false"
value="#{imageBean.streamedImageById}">
<f:param name="productId" value="#{_product.id}" />
</p:graphicImage>
</h:commandLink>
...
<p:dialog id="imgDialog" header="Image in Bigger" widgetVar="imgDialog">
<p:graphicImage styleClass="thumbnail_large" cache="false"
value="#{imageBean.getImageById()}">
</p:graphicImage>
</p:dialog>
in my ImageBean:
public void showImg(Long id) {
this.currentProductId = id;
PrimeFaces.current().executeScript("PrimeFaces.widgets['imgDialog'].show();");
}
public StreamedContent getImageById() throws Exception {
if (currentProductId != null) {
..
}
}
The image is clickable and popup correctly displayed, but for some reasons the full data table is refreshed (including all the images) after clicking, which is not user-friendly. Do you have any idea about my problem?
If you are not using Ajax, your entire page will be rerendered if you click a command link. You might want to replace your h:commandLink with a p:commandLink which gives you Ajax out of the box. Then, you want to rerender the dialog when that button is clicked (in order to contain the correct image) and simply show the dialog from the client side using the oncomplete attribute:
<p:commandLink action="#{imageBean.setCurrentProductId(_product.id)}"
update="imgDialog"
oncomplete="PF('imgDialog').show()">
...
</p:commandLink>
Please note that it's important that you choose the right bean scope. Ajax will not work with #RequestScoped beans. You probably want to use #ViewScoped.
Disclaimer - I am newbie to richfaces as I used to work on .net platform earlier :)
I am trying to change the theme of the RichFaces application with materialize css. I have a simple h:selectOneMenu as below
<h:selectOneMenu value="#{testBean.presetDate}" valueChangeListener="#{testBean.resetValues}" id="presetDate">
<f:selectItem itemValue="-1" itemDisabled="true" itemLabel="Select days" />
<f:selectItems value="#{testBean.listOfPresetDates}" />
<a4j:support event="onchange" ajaxSingle="true">
</a4j:support>
</h:selectOneMenu>
and my resetValues method inside testBean.java is as follows:
public void resetValues(ValueChangeEvent valueChangeEvent) {
//some processing here
}
and I have been initialising this selecOneMenu with materialize css multi_select() plugin as below:
$('select').material_select();
But whatever I do, the valueChangeListner doesn't trigger at all. I mean, it never calls the method in server. I also tried putting that method as actionListener in a4j:support and changing parameter of server method as ActionEvent, but even that doesn't help. Anything else I have to configure along with this?
Note: Earlier design had rich:combobox instead of selectOneMenu which was working fine with changeListener, but the plugin will not be able to convert this to required material select since, the above will not render select element, rather it renders table and inputs in DOM.
EDIT
Forgot to mention one thing. We are loading this page through ajax request as below:
<a4j:form id="pageForm" rendered="#{prevBean.selectedPage == 'bth'}">
<a4j:include viewId="/newPage.jsp" id="newPage" rendered="#{prevBean.selectedPage == 'bth'}" />
<script type="text/javascript">
jQuery(document).ready(function() {
initSelect_DatePicker();
});
</script>
</a4j:form>
This newPage.jsp contains above control. Will this be a cause for the above problem?
So I have this code:
<h:form id="serviceCustomFormForm">
<p:dialog id="parameterGroupAddDialog" widgetVar="parameterGroupAddDialog" header="#{messages.addParameterGroup}" modal="true" resizable="false">
<p:inputText value="#{serviceCustomFormBean.serviceParameterGroup.name}" styleClass="Wid90" />
<br />
<br />
<p:commandButton value="#{messages.save}" styleClass="Fright BlueButton" update="serviceCustomFormForm" actionListener="#{serviceCustomFormBean.addServiceParameterGroup}" oncomplete="PF('parameterGroupAddDialog').hide()" />
<p:commandButton value="#{messages.cancel}" styleClass="Fright RedButton" oncomplete="PF('parameterGroupAddDialog').hide()"/>
</p:dialog>
<div class="Container100">
<div class="ContainerIndent">
<p:commandButton value="#{messages.addParameterGroup}" icon="fa fa-plus-circle" styleClass="Fright CyanButton FloatNoneOnMobile" oncomplete="PF('parameterGroupAddDialog').show()" />
<div class="EmptyBox10 ShowOnMobile"></div>
</div>
</div>
</h:form>
When the page is first loaded the #PostConstruct method is called.
When I click the commandButton to open the dialog it's called again. And when I press the Cancel button inside the dialog it's called again.
This behavior does not occur in other parts of the application, and I can't see what I am missing here.
Update: As requested, the Bean code is here:
#ManagedBean
#ViewScoped
public final class ServiceCustomFormBean implements Serializable {
private ServiceParameterGroup serviceParameterGroup = new ServiceParameterGroup();
// Other attributes
#PostConstruct
private void init() {
// Reads attributes sent from previous page
}
public void addServiceParameterGroup() {
// Saves the serviceParameterGroup to database
}
// Getters and Setters
}
It's because the Commandbutton submits the form. You can
change to this:
<p:commandButton type="button" ...onclick="PF('parameterGroupAddDialog').hide()"
Type button tells primefaces not to submit the form. If the form isn't submitted oncomplete is never called. So it's onclick.
Try setting the following attributes to your 'Add Service' and 'Cancel' commandButton elements: partialSubmit="true" process="#this".
Code like this:
<commandButton value="#{messages.addParameterGroup}" ... partialSubmit="true" process="#this" ... />
By default, pf commandButtons try to submit the whole form, while in those two cases you just want to call the invoked method without doing a submit. With this, you are saying to primefaces that you don't want to submit it all (partialSubmit=true), and that you just want to process the invocation of the button itself (process=#this). Maybe that is your problem.
As an additional comment, i don't think getting the label values for the buttons from the bean is a good idea (unless you want to intentionally change the labels dynamically), because you will end up doing excessive requests to the bean. Better try using a messages properties file, as described in here http://www.mkyong.com/jsf2/jsf-2-0-and-resource-bundles-example/.
If I remember correctly, you should put your Dialog outside your main form, at the end of your body or use the appendTo="#(body)" param, and then, have another form inside the dialog.
After a long time dealing with this problem, I finally found the reason.
The annotation ViewScoped that I was importing in the backing bean was from the package javax.faces.view.
The correct one is javax.faces.bean.
Thanks for everyone that spend some time trying to help.
Sort of an odd question and I'd like to NOT give away code if possible, so I'll do my best to explain what is going on.
Basically, I have a commandButton that performs an AJAX action and then updates the entire form that it is inside of.
This form works like such:
<h:form id="tabform">
.....
<p:commandButton update=":tabform" value="Save" ajax="true" onstart="savingDialog.show();" onsuccess="savingDialog.hide();" actionListener="#{bean.saveContent}" /> <!-- styling makes it fixed position -->
.....
<p:editor id="ed1" />
<p:editor id="ed2" />
<p:editor id="ed3" />
<p:editor id="ed4" />
<p:editor id="ed5" />
<p:editor id="ed6" />
</h:form>
When I click the save button, and I am at like editor 5, it will save and then place me in the middle of editor 2. Not focus, but "focus of the browser view" (if that makes sense).
I can confirm it has everything to do with the update on the commandButton. It appears to put me half way in the middle of the tabform after the update.
Is there ANY way around this?
Use the scrollTo method on the RequestContext to scroll to a specific component after any server side action. Obviously this will require you devise a scheme to know beforehand, the component you want to level the page to. Without meaningful code from you, you can start off with the following:
public void saveContent(){
//your implementation here
RequestContext context = RequestContext.getCurrentInstance();
context.scrollTo("tabForm:ed5")
}
I want to implement a situation where the user enter a URL, and if a specified condition is true in my managed bean this URL will be opened in a new web page.
I found this possibility:
The “h:link” tag is useful to generate a link which requires to interact with the JSF “outcome” , but lack of “action” support make it hard to generate a dynamic outcome.
The “h:commandLink” tag is suck, the generated JavaScript is really scary! Not recommend to use this tag, unless you have a solid reason to support. But it supports the “action” attribute, which is what “h:link” lack of.
The “h:outputLink” is useful to generate a link which does not require to interact with the JSF program itself.
At last, it will be perfect if the “action” attribute is added into the “h:link“.
But I didn't find a way to launch the open web page from my managed bean after the condition is verified.
I'm using JSF2.0, Facelets and PrimeFaces 3.4.
To open the target in a new window using one of those link components, you need to specify target="_blank" attribute, but this will already open the target in a new window at the moment you click the link and does thus not depend on the response. You basically need to open the target in a new window at the moment the response has been arrived. The only way is returning a JavaScript window.open() call to the response so that it get executed in the webbrowser.
In standard JSF, you could just render JavaScript's window.open() conditionally.
<h:form>
<h:inputText value="#{bean.url}" />
<h:commandButton value="submit" action="#{bean.submit}">
<f:ajax execute="#form" render="#form" />
</h:commandButton>
<h:outputScript rendered="#{bean.valid}">window.open('#{bean.url}')</h:outputScript>
</h:form>
with
private String url;
private boolean valid;
public void submit() {
valid = validate(url);
}
// ...
In PrimeFaces, you could use RequestContext#execute() to specify JavaScript code which needs to be executed on complete of the response.
<h:form>
<p:inputText value="#{bean.url}" />
<p:commandButton value="submit" action="#{bean.submit}" />
</h:form>
with
private String url;
public void submit() {
if (validate(url)) {
RequestContext.getCurrentInstance().execute("window.open('" + url + "')");
}
}
// ...
Unrelated to the concrete problem: the ranty statements which you cited there are seemingly written by someone who know nothing about HTTP/HTML basics (limitations of GET vs POST and so on). Please take them with a good grain of salt.