I have commandButton component on my JSF page:
<p:commandButton id="period"
value="#{myBean.isMonthly == false ? 'Yearly' : 'Monthly'}"
action="#{myBean.doSomeOtherStuff()}"
update="period myDataTable">
</p:commandButton>
I'm trying to update a dataTable upon a click on the button above.
When I click it, the dataTable is updated as desired whereas the commandButton behaves weirdly, resulting in a display like:
Can someone help me understand the causes of such a weird situation and also tell a solution if possible?
NOTES:
JSF implementation and version: Mojarra (javax.faces-2.1.11.jar)
View technology: Facelets (XHTML)
Copy'n'paste'n'runnable example! (SSCCE) listed below:
FilterBean.java:
package com.turkcell.mdealer.bean.impl;
import org.springframework.stereotype.Component;
#Component
public class FilterBean {
private boolean monthly = true;
public String applyPeriod(String caller) {
monthly = !monthly;
return caller;
}
public boolean isMonthly() {
return monthly;
}
public void setMonthly(boolean monthly) {
this.monthly = monthly;
}
}
sample.xhtml:
<f:view xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:turkcell="http://turkcell.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui" xmlns:o="http://omnifaces.org/ui"
xmlns:of="http://omnifaces.org/functions"
xmlns:pm="http://primefaces.org/mobile" contentType="text/html"
renderKitId="PRIMEFACES_MOBILE">
<pm:page title="Bayi Raporlari">
<pm:view id="FaturasizAktivasyon" swatch="c">
<p:outputPanel id="FaturasizPanel">
<h:form id="FaturasizForm">
<pm:content>
<p:commandButton id="period"
value="#{filterBean.monthly == false ? 'Yearly' : 'Monthly'}"
action="#{filterBean.applyPeriod('sample')}" update="period">
</p:commandButton>
</pm:content>
</h:form>
</p:outputPanel>
</pm:view>
</pm:page>
</f:view>
General view of libraries:
I don't know the reason of the weird behaviour
However, you can use two conditionally rendered button to achieve the same effect:
<p:panelGroup>
<p:commandButton value="Monthly"
action="#{myBean.doSomeOtherStuff()}"
update="myDataTable #parent" rendered="#{myBean.isMonthly}" />
<p:commandButton value="Yearly"
action="#{myBean.doSomeOtherStuff()}"
update="myDataTable #parent" rendered="#{not myBean.isMonthly}" />
</p:panelGroup>
Related
edit: Based on Jasper's comment, the selection feature requires p:dataTable to be in a form, so my question is moot.
I have a DataTable outside of a form. When I submit the form (non-ajax), the field referenced by the selection attribute is set to null in my view. This happens for PrimeFaces 10.0.1 and higher. In 10.0.0 and 8.x, the field is not touched.
The field in the example is DtView.selectedEntry.
xhtml:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:p="http://primefaces.org/ui"
xmlns:h="http://xmlns.jcp.org/jsf/html">
<h:head>
<title>PrimeFaces Test</title>
</h:head>
<h:body>
<p:dataTable id="data-table" var="entry"
value="#{dtView.entries}"
rowKey="#{entry.id}"
selection="#{dtView.selectedEntry}"
selectionMode="single">
<p:column headerText="Entry">
<h:outputText value="#{entry}" />
</p:column>
</p:dataTable>
<h:form id="frmTest">
<div>
<p:outputLabel for="#next" value="Selected: "/>
<h:outputText id="selected-entry" value="#{dtView.selectedEntry}" />
</div>
<div>
<p:commandButton value="save input"
ajax="false"
imediate="true"
update="#form :data-table"
action="#{dtView.submit()}" />
</div>
</h:form>
</h:body>
</html>
View:
#Data
#Named
#ViewScoped
public class DtView implements Serializable {
private List<Product> entries;
private Product selectedEntry;
#PostConstruct
void setup() {
entries = List.of(
new Product(1, "entry 1"),
new Product(2, "entry 2"),
new Product(3, "entry 3")
);
selectedEntry = entries.get(0);
}
public String submit() {
System.out.println("Selected entry: " + selectedEntry);
return null;
}
}
Console (PrimeFaces 11.0.0 and then 10.0.0):
Selected entry: null
Selected entry: Product(id=1, name=entry 1)
To avoid the 'null' I can put p:dataTable inside a form, so it won't get processed during the apply request value phase or use ajax on the command button. I am not sure why the dataTable is outside a form in my real application to begin with.
I expected a value outside of a form not to be set in the view, but dataTable does not seem to follow this. Is the new PF behaviour more logical and my understanding is wrong?
The reason for this change seems to be located in SelectionFeature.
PF 8: just calls table.setSelection(null);:
https://github.com/primefaces/primefaces/blob/cd4fbdf1d9d4ae054da19b9a84001d0c34d142eb/src/main/java/org/primefaces/component/datatable/feature/SelectionFeature.java#L78
PF 10.0.0: decodeSingleSelection() does not call setSelection() because !rowKeys.isEmpty() evaluates to false (empty check disappears in 10.0.1):
https://github.com/primefaces/primefaces/blob/10.0.0/src/main/java/org/primefaces/component/datatable/feature/SelectionFeature.java#L84
11.0.0: decodeSingleSelection() eventually calls setSelection() to set the value in the view to null:
https://github.com/primefaces/primefaces/blob/11.0.0/primefaces/src/main/java/org/primefaces/component/datatable/feature/SelectionFeature.java#L87
I have a this simplified form to show the challenge:
It is a form with multiple tabs (2 in this MVCE).
My goal is to highlight both fields in case of validation failure (but only for tab it is failing for).
TabView (backing bean)
package betlista.so.pf.findComponent;
import com.sun.faces.component.visit.FullVisitContext;
import org.primefaces.PrimeFaces;
import org.springframework.stereotype.Component;
import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.component.UIInput;
import javax.faces.component.UIViewRoot;
import javax.faces.component.visit.VisitCallback;
import javax.faces.component.visit.VisitContext;
import javax.faces.component.visit.VisitResult;
import javax.faces.context.FacesContext;
import java.util.LinkedList;
import java.util.List;
#Component
public class TabView {
List<TabData> tabData = new LinkedList<>();
{
tabData.add(new TabData("name 1", "val1-a", null));
tabData.add(new TabData("name b", "val1-b", "val2-b"));
}
public List<TabData> getTabsData() {
return tabData;
}
public void save() {
boolean isValid = isValid();
if (isValid) {
// continue ...
}
}
private boolean isValid() {
boolean isOk = isOk();
if (isOk) {
return true;
}
FacesMessage message = new FacesMessage("Not saved!");
message.setSeverity(FacesMessage.SEVERITY_ERROR);
FacesContext context = FacesContext.getCurrentInstance();
context.addMessage(null, message);
final UIViewRoot viewRoot = context.getViewRoot();
List<UIInput> componentList = new LinkedList<>();
viewRoot.visitTree(new FullVisitContext(context), new VisitCallback() {
#Override
public VisitResult visit(VisitContext context, UIComponent target) {
if (target != null) {
final String id = target.getId();
if ("val1".equals(id) || "val2".equals(id)) {
if (target instanceof UIInput) {
componentList.add((UIInput) target);
}
}
}
return VisitResult.ACCEPT;
}
});
for (UIInput uiInput: componentList) {
uiInput.setValid(false);
}
context.validationFailed();
PrimeFaces.current().ajax().update("form");
final UIComponent val1 = context.getViewRoot().findComponent("val1");
return false;
}
private boolean isOk() {
return false;
}
}
in this simplified version isOk() returns false.
In a validation I know whether data for 1st or second tab is not ok and I'm trying to find a way how to highlight those two fields in tab.
I tried initially context.getViewRoot().findComponent(...), but I'm not able to "find it" (returns null). So to have access to the components I used this:
List<UIInput> componentList = new LinkedList<>();
viewRoot.visitTree(new FullVisitContext(context), new VisitCallback() {
#Override
public VisitResult visit(VisitContext context, UIComponent target) {
if (target != null) {
final String id = target.getId();
if ("val1".equals(id) || "val2".equals(id)) {
if (target instanceof UIInput) {
componentList.add((UIInput) target);
}
}
}
return VisitResult.ACCEPT;
}
});
so I have (in this case) all 4 components (but let say only those for first tab are invalid).
I'm trying to find a way how to identified which component belong to which tab (not sure whether to rely on a an order in list).
I was trying dynamic ID's, but it's not working, e.g. I added tab name (tabName)as attribute and used
<p:inputText id="#{cc.attr.tabName}-val2" ... />
I found no way how to add some custom flag/attribute whatever to be able to link component to a tab.
I was reading that ID can be dynamic once I'd use EL custom function (I mean I can use concatenation), but I was not able to find a resource describing it (I have no web.xml).
Code is available in GitHub.
myTab.xhtml (custom component)
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:f="http://java.sun.com/jsf/core" xmlns:p="http://primefaces.org/ui"
xmlns:composite="http://java.sun.com/jsf/composite">
<composite:interface>
<composite:attribute name="data" required="true" type="betlista.so.pf.findComponent.TabData" />
</composite:interface>
<composite:implementation>
<div class="ui-g">
<div class="ui-g-12">
<div class="ui-g-6">
<p:outputLabel value="Val 1:"/>
</div>
<div class="ui-g-6">
<p:inputText id="val1" value="#{cc.attrs.data.val1}" widgetVar="#{cc.attrs.data.tabName}-val1"/>
</div>
</div>
<div class="ui-g-12">
<div class="ui-g-6">
<p:outputLabel value="Val 2:"/>
</div>
<div class="ui-g-6">
<p:inputText id="val2" readonly="true" value="#{cc.attrs.data.val2}" widgetVar="#{cc.attrs.data.tabName}-val2"/>
</div>
</div>
</div>
</composite:implementation>
</html>
page.xhtml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:p="http://primefaces.org/ui"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:comp="http://xmlns.jcp.org/jsf/composite/comp">
<h:head>
<h:outputScript library="webjars" name="font-awesome/5.5.0/js/all.js"/>
</h:head>
<h:body styleClass="mainBody">
<h:form id="form">
<p:tabView id="tabView" value="#{tabView.tabsData}" var="tabVar">
<p:tab id="tab" title="#{tabVar.tabName}">
<comp:myTab data="#{tabVar}" />
</p:tab>
</p:tabView>
<p:commandButton value="Save" action="#{tabView.save()}" process="#form" update="#form" />
<p:growl id="growl" life="3000"/>
</h:form>
</h:body>
</html>
I got very confused by debugger...
The simplest solution is to add label like this:
<p:inputText id="val1" value="#{cc.attrs.data.val1}" label="someLabel1" />
...what I missed earlier is, that label is not a field therefor it was difficult to find it, it is available under stateHelper:
Probably better solution (despite label I cannot see in generated HTML) is to use custom attribute like this (I'd bet I tried that as well, apparently not):
<p:inputText id="val2" readonly="true" value="#{cc.attrs.data.val2}">
<f:attribute name="someAttribute" value="value2" />
</p:inputText>
and it's easily accessible:
I have a very simple xhtml file where a panelGroup containing a commandButton is added to the page on clicking toggle button but this dynamically added commandButton fails to execute its actionlistener on being clicked.
Complete code below:
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.org/ui">
<h:head>
</h:head>
<h:body>
<h:panelGroup id="checkDyna">
<h:panelGroup rendered="#{listRetriever.booleanStatus}" >
<h:form>
<p:commandButton value="check" process="#all" actionListener="#{listRetriever.xx()}"/>
</h:form>
</h:panelGroup>
</h:panelGroup>
<h:form>
<p:commandButton value="Toggle" actionListener="#{listRetriever.toggleBooleanStatus()}" update=":checkDyna"/>
</h:form>
</h:body>
</html>
Bean
#ManagedBean(name = "listRetriever")
#RequestScoped
public class ListRetriever implements Serializable {
private boolean booleanStatus;
public void toggleBooleanStatus(){
if (!booleanStatus)
booleanStatus=true;
}
public void xx(){
System.out.println("Invoked***");
}
public boolean isBooleanStatus() {
return booleanStatus;
}
public void setBooleanStatus(boolean booleanStatus) {
this.booleanStatus = booleanStatus;
}
}
On removing rendered="#{listRetriever.booleanStatus}" actionlistener is successfully invoked.
On making the bean ViewScoped too the problem is eliminated but I dont want to make it wider than RequestScoped.
I had this p:commandButton within a conditionally rendered panel whose conditional expression for rendering was evaluating to false while I was trying to execute the actionlistener. This was the cause of actionlistener not getting executed.
I want to create JSF page with tabs. Something like this. But I wonder if I choose to do this with Jquery can I implement lazy loading - when I click a tab on the JSF page the content is generated when the tab is opened. Is it possible to implement lazy loading of tabs in pure JSF? And I suppose that I can easily implement AJAX in both cases.
Best wishes
The Primefaces Tabview component supports lazy loading.
Quote from the showcase:
Tab contents can be lazy loaded with ajax as well, when dynamic
attribute is set to "true" only the active tab's content will be
rendered and clicking on a lazy tab will fetch the tab contents with
ajax. This behavior is handy to save bandwith and reduce page size
when dealing with tabs having a lot of content.
Quick example from the showcase:
<h:form id="form">
<p:tabView id="tabView" dynamic="true" cache="true">
// tabs
</p:tabView>
</h:form>
The cache attribute is used to prevent ajax reloading of tab content if you toggle between tabs.
Note: If you want your tabs beans be Session Scope then read instructions in the buttom of the Answer...
Since you are don't want to use any third party Libarary here is a PureJSF + jQuery example
JSF + Jquery + Ajax Lazy Loading + View Scope Beans Example...
B.T.W here is how it looks like eventually :
You can look at the web server console for the print outs of #PostConstruct and the #PreDestroy when you click on each tab...
The content of the tab - the xhtml page and its bean will be loaded upon tab click (Lazy Loading) and will be destroyed upon click on other tab,
I suggest you to create a new project and slowly place all the files inside it and start playing and looking into it... its 100% working , but I placed some print outs just to see that it is really working...
The Example is very simple and straight forward....
First Of all go to jQueryUI and download it(1.8.18)
and place jquery-1.7.1_.min.js and jquery-ui-1.8.18.custom.min.js in WebContent\resources\js and jquery-ui-1.8.18.custom.css in WebContent\resources\css
Now to the other files...
myTabs.xhtml
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:c="http://java.sun.com/jsp/jstl/core">
<h:head>
<h:outputScript library="js" name="jquery-1.7.1_.min.js" target="head" />
<h:outputScript library="js" name="jquery-ui-1.8.18.custom.min.js" target="head" />
<h:outputStylesheet library="css" name="jquery-ui-1.8.18.custom.css" target="head" />
<h:outputScript library="js" name="mytabs.js" target="head" />
</h:head>
<h:body>
<f:view>
<h:form prependId="false">
<h:panelGroup id="tabs" layout="block">
<ul>
<c:forEach items="#{myTabs.tabs}" var="tab">
<li>#{tab.tabid}</li>
<h:commandButton id="button_#{tab.tabid}" value="TabClick" action="#{myTabs.switchPages(tab.tabid)}" style="display:none">
<f:ajax render="tabs"></f:ajax>
</h:commandButton>
</c:forEach>
</ul>
<c:forEach items="#{myTabs.tabs}" var="tab">
<h:panelGroup id="#{tab.tabid}" layout="block" rendered="#{tab.tabid eq myTabs.selectedTab}">
<ui:include src="#{tab.tabfilename}"></ui:include>
</h:panelGroup>
</c:forEach>
</h:panelGroup>
</h:form>
</f:view>
</h:body>
</html>
MyTabs.java
package pack;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
#ManagedBean
#SessionScoped
public class MyTabs{
#PostConstruct
public void init(){
tabs = new ArrayList<MyTabObject>();
tabs.add(new MyTabObject("tab1.xhtml", "tab1"));
tabs.add(new MyTabObject("tab2.xhtml", "tab2"));
tabs.add(new MyTabObject("tab3.xhtml", "tab3"));
}
String selectedTab="tab1";
public String getSelectedTab() {
return selectedTab;
}
public void setSelectedTab(String selectedTab) {
this.selectedTab = selectedTab;
}
public String switchPages(String selTab) {
selectedTab = selTab;
return "myTabs.xhtml";
}
List<MyTabObject> tabs;
public List<MyTabObject> getTabs() {
return tabs;
}
public void setTabs(List<MyTabObject> tabs) {
this.tabs = tabs;
}
}
MyTabObject
package pack;
public class MyTabObject{
String tabfilename;
String tabid;
public String getTabfilename() {
return tabfilename;
}
public void setTabfilename(String tabfilename) {
this.tabfilename = tabfilename;
}
public String getTabid() {
return tabid;
}
public void setTabid(String tabid) {
this.tabid = tabid;
}
public MyTabObject(String tabfilename, String tabid) {
super();
this.tabfilename = tabfilename;
this.tabid = tabid;
}
}
Tab1Page , (Tab2Page and Tab3Page are exactly the same , just change the number in all places)
package pack;
import java.io.Serializable;
import java.text.Format;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
#ManagedBean
#ViewScoped
public class Tab1Page implements Serializable{
/**
*
*/
private static final long serialVersionUID = 254415216070877770L;
// Constants
public final static String hashKey = "tab1PageTab";
public String actionString = "";
#PostConstruct
public void post(){
Format formatter;
Date date = new Date();
// Time formate 01:12:53 AM
formatter = new SimpleDateFormat("hh:mm:ss a");
tabName = formatter.format(date);
System.out.println("Tab1Page\t"+tabName+"\t#PostConstruct...");
}
#PreDestroy
public void destroy(){
Format formatter;
Date date = new Date();
// Time formate 01:12:53 AM
formatter = new SimpleDateFormat("hh:mm:ss a");
tabName = formatter.format(date);
System.out.println("Tab1Page\t"+tabName+"\t#PreDestroy...");
}
String tabName;
public String getTabName() {
return this.getClass().getName().substring(this.getClass().getName().lastIndexOf("."))+"\t"+tabName;
}
public void setTabName(String tabName) {
this.tabName = tabName;
}
public String getActionString() {
return actionString;
}
public void setActionString(String actionString) {
this.actionString = actionString;
}
}
tab1.xhtml (tab2.xhtml and tab3.xhtml are exactly the same - just replace the numbers)
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:c="http://java.sun.com/jsp/jstl/core">
<h:panelGroup>
<h:form>
<h:outputText value="#{tab1Page.tabName}" />
</h:form>
</h:panelGroup>
</ui:composition>
and to the last file
mytabs.js (place it in WebContent\resources\js)
$(document).ready(function () {
$("#tabs").tabs();
});
$(window).load(function() {
jsf.ajax.addOnEvent(function (data) {
if (data.status === "success") {
$("#tabs").tabs();
}
});
});
In order to use Session Scope Beans:
The method switchPages in MyTabs.java should be void and not to return anything, like this
public void switchPages(String selTab) {
selectedTab = selTab;
}
It's not a problem at all implement an ajax tab with jQuery UI.
See the documentation of jQuery Tabs with ajax here and click on "view source" to find the code you need.
You can look at the book Core Java Server Faces third edition page 339 to see how you can implement simple tabs with h:panelGrid.
The output is something like this:
This is the code example from the book:
...
<h:form>
<h:panelGrid styleClass="tabbedPane" columnClasses="displayPanel">
<!-- Tabs -->
<f:facet name="header">
<h:panelGrid columns="4" styleClass="tabbedPaneHeader">
<h:commandLink tabindex="1"
title="#{msgs.jeffersonTooltip}"
styleClass="#{tp.jeffersonStyle}"
actionListener="#{tp.jeffersonAction}">
#{msgs.jeffersonTab}
</h:commandLink>
...
</h:panelGrid>
</f:facet>
<!-- Tabbed pane content -->
<ui:include src="washington.xhtml" />
<ui:include src="roosevelt.xhtml" />
<ui:include src="lincoln.xhtml" />
<ui:include src="jefferson.xhtml" />
</h:panelGrid>
</h:form>
...
This is the description:
The tabbed pane is implemented with h:panelGrid. Because we do not specify
the columns attribute, the panel has one column. The panel’s header—defined
with an f:facet tag—contains the tabs, which are implemented with another
h:panelGrid that contains h:commandLink tags for each tab. The only row in the panel
contains the content associated with the selected tab.
When a user selects a tab, the associated action listener for the command link is
invoked and modifies the data stored in the backing bean. Because we use a
different CSS style for the selected tab, the styleClass attribute of each h:commandLink
tag is pulled from the backing bean with a value reference expression.
As you can see from the top picture in Figure 8–11, we have used the title
attribute to associate a tooltip with each tab. Another accessibility feature is the
ability to move from one tab to another with the keyboard instead of the
mouse. We implemented that feature by specifying the tabindex attribute for
each h:commandLink.
The content associated with each tab is statically included with the JSP include
directive. For our application, that content is a picture and some text, but
you could modify the included JSF pages to contain any set of appropriate
components. Notice that even though all the JSF pages representing content are
included, only the content associated with the current tab is rendered. That is
achieved with the rendered attribute—for example, jefferson.xhtml looks like this:
Putting It All Together
<h:panelGrid columns="2" columnClasses="presidentDiscussionColumn"
rendered="#{tp.jeffersonCurrent}">
<h:graphicImage value="/images/jefferson.jpg"/>
<span class="tabbedPaneContent">"#{msgs.jeffersonDiscussion}"</span>
</h:panelGrid>
Figure 8–12 shows the directory structure for the tabbed pane application and
Listings 8–14 through 8–17 show the most important files.
Unfortunately I don't know how to add lazy loading and AJAX support to this code.
I'm using the component rich:fileUpload for uploading files to my server the problem is that those files go along with a form that the user fills, so I wanna use one external button for doing this.
The user select the files to upload, fill the form and then click a "Submit" button at the bottom of the page. This upload the file with the form. I've tried it like this:
I'm able to hide the button inside the panel of fileUpload so the user don't click on it.
<rich:fileUpload id="fileUploadId"
style="width: 100%; height: 130px;"
fileUploadListener="#{documentsBean.listener}"
maxFilesQuantity="1"
uploadButtonClass="display-none"
uploadButtonClassDisabled="display-none">
</rich:fileUpload>
And what I've tried with the button is
<a4j: commandButton id="uploadFormButton"
value="Attach"
onclick="#{rich:component('fileUploadId')}.submitForm();"
oncomplete="#{rich:component('fileUploadId')}.clear(); return false;"/>
But it doesn't work.
I don't know if there is a way to do exactly what you want, but here is another solution you can use :
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:rich="http://richfaces.org/rich"
xmlns:a4j="http://richfaces.org/a4j"
xmlns:st="http://spectotechnologies.com/jsf"
xmlns:t="http://myfaces.apache.org/tomahawk">
...
<h:form enctype="multipart/form-data">
... your fields ...
<t:inputFileUpload value="#{bean.document}" />
<h:commandButton value="Submit" actionListener="#{bean.onButtonSubmitClick}" />
</h:form>
</html>
and the bean :
#ManagedBean
#RequestScoped
public class Bean
{
private UploadedFile m_oDocument;
public void setDocument(UploadedFile p_oDocument)
{
m_oDocument = p_oDocument;
}
#UploadedFileNotEmpty
#UploadedFileSize(max="10000000")
#UploadedFileExtension(accept="doc,docx,pdf,txt,rtf,xls,xlsx,zip,rar,jpg,jpeg,jpe,bmp,gif,png,csv,ppt,pptx,odp,pic,odt,ods")
public UploadedFile getDocument()
{
return m_oDocument;
}
public void onButtonSubmitClick(ActionEvent p_oEvent)
{
...
}
}
Hope this helps!