In a JSF 2.1 wep app, I have a column of a dataTable that contains a commandButton. The action triggered by the commandButton may throw an error. I want to open a dialog in case no errors are thrown, or a box containing the error message in the other case.
JSF
<h:form>
<p:dataTable var="foo" value="#{myBean.foos}" >
<p:column>#{foo.id}</p:column>
<p:column>
<p:commandButton title="Action" action="#{myBean.action()}" onComplete="handleResult(xhr, status, args)" >
<f:setPropertyActionListener value="#{foo}" target="#{myBean.selectedFoo}" />
</p:commandButton>
</p:column>
</p:dataTable>
</h:form>
JavaScript
function handleRequest(xhr, status, args) {
if (!args.success) {
displayBox(args.errorMsg);
} else {
displayDialog();
}
}
MyBean
@ManagedBean
@ViewScoped
public class MyBean {
private List<Foo> foos;
private Foo selectedFoo;
public void action() {
try {
// business logic
} catch (Exception ex) {
RequestContext rContext = RequestContext.getCurrentInstance();
rContext.addCallbackParam("success", false);
rContext.addCallbackParam("errorMsg", ex.getMessage());
}
}
}
The only solution I can think of is using PrimeFaces' RequestContext.callBackParam()
and writing a JS function that reads it and decides what to open.
Is there a smoother way? I'd consider to leverage the concept of validation, if possible, but I can't find an example of how to intercept the error in JS.
The canonical way is to just add a global faces message (thus, with null
client ID).
public void action() {
try {
// business logic
} catch (Exception ex) {
context.validationFailed();
context.addMessage(null, new FacesMessage(
FacesMessage.SEVERITY_ERROR, ex.getMessage(), null));
}
}
(calling FacesContext#validationFailed()
will cause #{facesContext.validationFailed}
in EL to evaluate true
; this is normally set in case of ValidatorException
)
Then, to display a box for global message only, just use <p:messages globalOnly="true">
.
<p:messages globalOnly="true" autoUpdate="true" />
And to display a dialog on successful outcome, let it render when a successful postback is performed:
<p:outputPanel autoUpdate="true">
<p:dialog visible="true" rendered="#{facesContext.postback and not facesContext.validationFailed}">
A successful postback is performed!
</p:dialog>
</p:outputPanel>
Replace if necessary autoUpdate="true"
of one or the both components by update="messagesId dialogPanelId"
so that it's only triggered when the particular button is pressed.