How can a custom-validator know which commandButton was clicked - jsf-2

my form has several "submit" buttons,
and the validation of some of the fields depends on which was pressed.
How can I find that out in my custom validator?

The button's client ID get also generated as name of the <input type="submit">. The name=value of the pressed <input type="submit"> get also sent as request parameters. So you could just check for that in the request parameter map.
E.g.
<h:form id="formId">
...
<h:commandButton id="button1" ... />
<h:commandButton id="button2" ... />
</h:form>
with the following in validate() implementation:
Map<String, String> params = context.getExternalContext().getRequestParameterMap();
if (params.containsKey("formId:button1")) {
// Button 1 is pressed.
}
else if (params.containsKey("formId:button2")) {
// Button 2 is pressed.
}

For JSF there will be inbuilt validation messages which will get displayed during Errors..or you can use Validation attributes like "validator & validatorMessages " in primefaces in their respective Tags.

Related

Primefaces 5.1 Dialog Framework dialogReturn event handler not called

I'm new to JSF and primefaces. I'm using the Primefaces Dialog Framework to pop a modal terms of service agreement. The problem I'm having is that my dialogReturn event handler is not invoked when the dialog closes and the modal overlay remains on the page although the dialog itself closes. The modal overlay may be a red herring because the dialogReturn method is not invoked when the dialog is not modal either.
Here are the relevant pieces of code:
The form from which the dialog is created:
<h:form prependId="false">
<ul>
<ui:repeat value="#{serviceEditor.service.subsystems}" var="ss">
<li>
<em>#{ss.name}</em> - #{ss.description}<br/>
<ui:fragment rendered="#{identity.loggedIn}">
<ui:fragment rendered="#{grantManager.hasAccess(ss)}">
(You have access to this dataset.)
<h:commandButton value="Discontinue Access" action="#{grantManager.unrequestAccess(ss)}"/>
</ui:fragment>
<ui:fragment rendered="#{!grantManager.hasAccess(ss)}">
<p:commandButton value="Request Access"
actionListener="#{serviceDialog.display(ss)}"
styleClass="btn btn-primary" >
<p:ajax event="dialogReturn"
listener="#{serviceEditor.acceptDialogHandler}" />
</p:commandButton>
</ui:fragment>
...
ServiceEditor is annotated #Named #Stateful #ConversationScoped
The actionListener code for the dialog display:
public void display (ServiceSubsystem sub)
{
if (sub == null)
{
log.error("Service Accept dialog attempt with null subservice. Lose.");
FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_INFO, "Subservice Unavailable", "We seem to have misplaced that service. This has been logged for investigation.");
RequestContext.getCurrentInstance().showMessageInDialog(message);
return;
}
log.info("svcDlg: Displaying accept dialog for service: {}.{}", sub.getService().getName(), sub.getName());
this.sub = sub;
Map<String, Object> dlgOpts = new HashMap<>(2);
dlgOpts.put("modal", true);
RequestContext.getCurrentInstance().openDialog("serviceAcceptDialog", dlgOpts, null);
log.info("svcDlg: Did that accept dialog work out?");
}
The actionListener code for the accept command button in the dialog:
public void accept ()
{
log.info("Accepted {}.{}", sub.getService().getName(), sub.getName());
...
String destination = "/service?faces-redirect=true&uuid=" + sub.getService().getUuid();
log.info("Sending user to: {}", destination);
RequestContext.getCurrentInstance().closeDialog(destination);
}
And finally the dialog return listener that is not invoked:
public void acceptDialogHandler (SelectEvent event)
{
String dest = (String) event.getObject();
log.info("Service accept dialog closed. sending here: ", dest);
((ConfigurableNavigationHandler) FacesContext.getCurrentInstance().getApplication().getNavigationHandler())
.performNavigation(dest);
}
What did I miss in the documentation? Or is this a bug?
I think you can try to use primefaces dialog component, is simpler.
To show or close the dialog you only need to invoke it:
PF('widgetVarDialogName').hide();
PF('widgetVarDialogName').show();
You can open or close it in view actions, for example:
<p:commandButton
value="Open dialog"
type="button"
onclick="PF('widgetVarDialogName').show()" />
<p:commandButton
value="Do Action"
action="#{myBean.myAction()}"
oncomplete="PF('widgetVarDialogName').hide();" />
Also, you can invoke it from the bean if you want.
RequestContext.getCurrentInstance().execute("PF('widgetVarDialogName').show()");
RequestContext.getCurrentInstance().execute("PF('widgetVarDialogName').hide()");
(Remember, the dialog must be placed inside the form)
I see you work a lot with the rendered="..." attribute. From what I experienced the <p:ajax event="dialogReturn" /> is not getting fired if itself or a parent element is not rendered.
So have a look in your public void accept() method. If you change some state so that a rendered attirbute of a parent element of the <p:ajax event="dialogReturn" /> namely rendered="#{!grantManager.hasAccess(ss)}" and/or rendered="#{identity.loggedIn}" would evaluate to false then the listener would not be executed.
EDIT
A workaround just came to my mind. One can avoid the problem with the same workaround as if you want to trigger dialog framework from a <p:menuitem /> (Primefaces Dialog Framework — dialogReturn event from menuitem).
Simply create a separate button somewhere outside of the possibly not rendered area and trigger it via javascript.
Not tested code example:
<ui:fragment
id="fragment"
rendered="#{...}">
<h:commandButton
id="pseudo_button"
value="..."
onclick="document.getElementById('real_button').click()" />
</ui:fragment>
<h:commandButton
id="real_button"
action="#{bean.realWorkHere()}"
update="fragment"
style="display:none;">
<p:ajax
event="dialogReturn"
listener="#{...}" />
</h:commandButton>

commandButton doesn't set correctly f:param if it got a javascript method in onclick event

Between two JSF views xhtmls (both have view scoped backing beans) I would like to pass parameters if the user click a link or a button. If I have an attribute onclick with a JavaScript function to open another page (in this page I would like to use the parameters set in the first page) to the commandButton or commandLink I get the f:param attributes to be \'currentAccess\':\'3\',\'gridNo\':\'5\', and if I don't have an onclick attribute I have it right 'currentAccess':'3','gridNo':'5',
If I have:
<h:commandButton action="#{statisticsBean.showAccessIncorectAnswers()}" target="_blank"
value="#{strings.whatHaveDoDoneWrong}" rendered="#{o.date != '-' and o.answerNoWrong != 0}">
<f:param name="currentAccess" value="#{o.currentAccess}"/>
<f:param name="gridNo" value="#{o.noGrid}"/>
<f:param name="gridCategory" value="#{o.category}"/>
</h:commandButton>
the HTML rendering looks like:
<input type="submit" name="j_idt73:0:j_idt74:j_idt77" value="Ce ai gresit" onclick="mojarra.jsfcljs(document.getElementById('j_idt73:0:j_idt74'),{'j_idt73:0:j_idt74:j_idt77':'j_idt73:0:j_idt74:j_idt77','currentAccess':'1','gridNo':'5','gridCategory':'Drept Procesual Civil'},'');return false" />
which is good, I have access to the parameters (f:viewpara or FacesContext , I use the last one likeFacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("currentAccess"))
BUT
If I have:
<h:commandButton action="#{statisticsBean.showAccessIncorectAnswers()}" target="_blank"
onclick="confirmGridStatistics('#{strings.doYouWantToSeeTheWrongAnswersInAccessNo} #{o.currentAccess} #{strings.fromDate} #{o.date}?');"
value="#{strings.whatHaveDoDoneWrong}" rendered="#{o.date != '-' and o.answerNoWrong != 0}">
<f:param name="currentAccess" value="#{o.currentAccess}"/>
<f:param name="gridNo" value="#{o.noGrid}"/>
<f:param name="gridCategory" value="#{o.category}"/>
</h:commandButton>
WITH a JavaScript function in onclick event I get the rendering:
<input type="submit" name="j_idt73:2:j_idt74:j_idt77" value="Ce ai gresit" onclick="jsf.util.chain(this,event,'confirmGridStatistics(\'Vrei sa vezi raspunsurile gresite in accessul 3 din data de 16-05-2013?\');','mojarra.jsfcljs(document.getElementById(\'j_idt73:2:j_idt74\'),{\'j_idt73:2:j_idt74:j_idt77\':\'j_idt73:2:j_idt74:j_idt77\',\'currentAccess\':\'3\',\'gridNo\':\'5\',\'gridCategory\':\'Drept Procesual Civil\'},\'\')');return false" />
and in the second views backing bean I get null for the parameters from the FacesContext. Why is that?
UPDATE
I thought that
FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().put("currentAccess", access); in the action method whould solve it. But it doesn't, it gives me a java.lang.UnsupportedOperationException
I don't know why this is happening.
I have resolved the my issue with a hack. I still don't know why is the issue described with the parameters.
My solution (I know it`s a hack):
the JavaScipt function among other thing opened my second view (to which I wanted to pass the parameters)
so I have put the parameters (which I want to pass) to the JavaScipt function
<h:commandButton action="#{statisticsBean.showAccessIncorectAnswers()}" target="_blank"
onclick="confirmGridStatistics('#{strings.doYouWantToSeeTheWrongAnswersInAccessNo} #{o.currentAccess} #{strings.fromDate} #{o.date}?'
, '#{o.currentAccess}', '#{o.noGrid}', '#{o.category}');"
value="#{strings.whatHaveDoDoneWrong}" rendered="#{o.date != '-' and o.answerNoWrong != 0}"/>
and the second view request URL looks like http://myserver:port/access.xhtml?currentAccess=34&noGrid=3&category=category
and in the second view backing bean I access the parameters with
HttpServletRequest request = (HttpServletRequest)FacesContext.getCurrentInstance().getExternalContext().getRequest();
String currentAccess= request.getParameter("currentAccess");
STILL
If anybody knows why is the initial issue that I would appreciate it to share.
Thank you.

Displaying a message from managed bean with primefaces confirmation dialog component

in my page , i'm trying to display a confirmation dialog after clicking a button .In the confirmation dialog i used the attribute message to display it , this message is taken value after clicking the button . So i did it like that :
<p:commandButton value="Delete" update="testPlanetree" id="deleteBtn"
disabled="#{projectTestManagementMB.disable}" oncomplete="deleteConfirmation.show()"
action="#{projectTestManagementMB.testFn}"/>
<p:confirmDialog id="confirmDialog" message="#
{projectTestManagementMB.deleteConfirmationMsg}"
header="Confirming Deleting Process" severity="alert"
widgetVar="deleteConfirmation">
<p:commandButton id="confirm" value="Yes Sure" update="messages"
oncomplete="deleteConfirmation.hide()" />
<p:commandButton id="decline" value="Not Yet"
onclick="deleteConfirmation.hide()" type="button" />
</p:confirmDialog>
ProjectTestManagementMB Managed Bean :
private String deleteConfirmationMsg;//with getters and setters
public void testFn(){
deleteConfirmationMsg="do you want to delete ...";
}
The problem is that the deleteConfirmationMsg never take the value "do you want to delete ..." (is always empty)
Any idea will be appreciated
The <p:confirmDialog> has already generated its HTML representation on the very first HTTP request returning the page with the form and the dialog. It's merely hidden by CSS and is supposed to be shown/hidden by JS. When you change the confirm message afterwards in a bean action method, then it won't be reflected in the generated HTML output as long as you don't ajax-update it.
So, in order to get the changed message being reflected, you'd need to update the HTML representation of the <p:confirmDialog> in the client side before showing it in the oncomplete. You can for this use the update attribute of the command button which should show the dialog.
<p:commandButton ... update="confirmDialog testPlanetree">
try this i should works :
<p:commandButton value="Delete" update="testPlanetree" id="deleteBtn" actionListener="#
{projectTestManagementMB.testFn}"
disabled="# {projectTestManagementMB.disable}"
oncomplete="deleteConfirmation.show()" />

JSF - Richfaces, process submitted form data and then confirm to continue or cancel

I want to show a confirmation dialog to continiue or cancel a save operation when a form is submitted. I have a form with a save button which is calling an action methode to persist data in the form.
When save button is clicked, a file will be readed on serverside before the form data is persisted. Data from the file will be joined into form data and then te form data will be persisted. I need some values from the form to define which file will be readed. There is no problem so far. When a FileNotFoundException throwed or the neccessary data from the file is not found, then i want to show a confirmation dialog to continiue or cancel save operation with caused message.
Does anybody have some examples or any ideas how to handle this? Do i need to use a4j? Thanks.
I am using Rifchfaces 3.3.3 and Seamframework 2.2.
At first i have to correct my question title. It is not going on "processing submitted form data" but a form data that will be submitted after some validation.
Now the solution.
For example I have following in my form:
some filelds
an a4j:commandButton to reRender the fields and perform doSomeStuff() action
an hidden h: or a4j:commandButton to submit the form.
1- User clicks on 'fake' submit button which is an a4j:commandButtton,
2- Ajax call updates fields in reRender attribute
3- After that,method doSomeStuff() is performed with rerendered field values
4- In the end Javascript will run to submit form or not.
Form:
<h:form id="myForm">
<h:inputText id="name" value="#{personHome.person.name}"/>
<h:inputText id="surname" value="#{personHome.person.surname}"/>
<a:commandButton value="Save" reRender="name, surname"
action="#{personHome.doSomeStuff()}"
oncomplete="return checkMessage('#{personHome.success}')"
id="a4jSave" />
<h:commandButton id="save" value="Save"
action="#{personHome.persist}"
style="visibility:hidden" />
</h:form>
JavaScript:
<script language="javascript">
function checkMessage(success) {
if(success =='false')
{
return confirm('Do you want to submit this form?') ? submitForm() : false;
} else {
submitForm ();
}
}
function submitForm() {
document.getElementById('myForm:save').click();
return false;
}
</script>
Yes you need to use a4j.
Try something like that (non tested, but follow the algorithm) :
<a4j:commandButton onclick="if(messageHasToBeDisplayed){Richfaces.showModalPanel('modalId');}else{doSomeStuff();}" />
...
<a4j:jsFunction name="doSomeStuff" action="#{controller.doSomeStuff}" reRender="..."/>
This shows you how to display a modal panel if necessary.
Without more code I can't help you more, but I think this should help you...

JSF field highlighting with ajax posts?

I'm building on BalusC's solution to highlight and focus fields in JSF. My plan is to output a JSON array with ids and then have a method be called which will process this array. This works fine when I don't use <f:ajax/>
Here is my phase listener solution:
public void beforePhase(PhaseEvent event) {
FacesContext facesContext = event.getFacesContext();
List<String> highlightFields = new ArrayList<String>();
Iterator<String> highlightFieldsItr = facesContext
.getClientIdsWithMessages();
while (highlightFieldsItr.hasNext()) {
StringBuilder sb = new StringBuilder();
sb.append("#");
sb.append(highlightFieldsItr.next().replaceAll(":", "\\\\:"));
highlightFields.add(sb.toString());
}
JSONArray jsonHighlightFields = new JSONArray(highlightFields);
facesContext.getExternalContext().getRequestMap()
.put("errorFields", jsonHighlightFields.toString());
}
Basically this would produce errorFields value with something like ["#some\:id1", "#some\id2"]. Then I can do something like this in my root layout file:
<script>
var errorFields = ${errorFields}; // This will xlate to ["#some\\:id1", "#some\\:id2"
$(document).ready(function(){
processInputErrors(errorFields);
});
</script>
With a processInputErrors function like this:
function processInputErrors(ids) {
for (id in ids) {
if (focus == false) {
jQuery(ids[id]).focus();
focus = true;
}
jQuery(ids[id]).addClass('input-error');
}
}
However, I need to somehow obtain this list in the function which gets called on success of an ajax post.
Now f:ajax does have the onevent attribute and this function does get called, but I'm not sure exactly what it gets passed. How would I be able somehow pass the invalid Ids from the phase listener to this function? It seems to be passed an object which represents the HTMLInputElement?
<f:ajax event="change" onevent="test" render="test test_msg" immediate="true" />
Happy to hear about alternative suggestions or ideas. The goal is basically to focus and highlight the field(s) which are invalid not only on a full post-back but also when using f:ajax.
Thanks!
That article was more targeted on JSF 1.x. JSF 2.x offers now a lot of advantages of which the following are beneficial for your particular requirement:
You can refer the current component in EL by #{component}. In case of input components this is the UIInput which in turn has an isValid() method. This could be used in styleClass attribute.
You can use <f:ajax> to re-render parts of the view, also <script> elements.
1+1 is...
<h:inputText id="input1" value="#{bean.input1}" required="true" styleClass="#{component.valid ? '' : 'error'}">
<f:ajax render="#this input1message focus" />
</h:inputText>
<h:message id="input1message" for="input1" />
...
<h:inputText id="input2" value="#{bean.input2}" required="true" styleClass="#{component.valid ? '' : 'error'}">
<f:ajax render="#this input2message focus" />
</h:inputText>
<h:message id="input2message" for="input2" />
...
<h:panelGroup id="focus"><script>jQuery(":input.error:first").focus();</script></h:panelGroup>
No need for a PhaseListener anymore. You could if necessary wrap the input markup boilerplate in a composite component or a tag file.
Back to your concrete question about the onevent attribute, check this answer: JSF 2: How show different ajax status in same input?

Resources