Inconsistent behavior between <p:commandLink> and <p:commandButton> - jsf

I have a delete confirmation dialog:
<p:confirmDialog id="deleteConfirmDialog"
header="#{i18n['confirm-deletion']}"
widgetVar="pnp_delete_confirmDialog" closeable="false"
appendToBody="true">
<f:facet name="message">
<h:outputFormat id="deleteConfirmMessage"
value="#{i18n['confirm-subscription-deletion']}">
<f:param value="#{subscriptions.deleteSelected.title}" />
</h:outputFormat>
</f:facet>
<h:form id="pnpConfirmDeleteForm">
<p:commandButton id="deleteActionConfirmed"
action="#{subscriptions.delete}" value="#{i18n['delete']}"
type="button" process="#this" update=":pnpEditForm :pnpExistingForm"
oncomplete="pnp_delete_confirmDialog.hide()" />
<p:commandLink id="deleteActionConfirmedLink"
action="#{subscriptions.delete}" process="#this"
update=":pnpEditForm :pnpExistingForm"
oncomplete="pnp_delete_confirmDialog.hide()">#{i18n['delete']}</p:commandLink>
<p:commandButton id="deleteActionCancelled" value="#{i18n['cancel']}"
type="button" onclick="pnp_delete_confirmDialog.hide()" />
</h:form>
</p:confirmDialog>
You will notice that the deleteActionConfirmed button and the deleteActionConfirmedLink link have the exact same action, process, update, and oncomplete attributes. However, the link works as expected and the button does nothing. Looking at the generated markup:
<form enctype="application/x-www-form-urlencoded"
action="/primefaces-quickstart/xhtml/pnp-configuration.xhtml" method="post"
name="pnpConfirmDeleteForm" id="pnpConfirmDeleteForm">
<input type="hidden" value="pnpConfirmDeleteForm" name="pnpConfirmDeleteForm">
<button type="button"
class="ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only"
name="pnpConfirmDeleteForm:deleteActionConfirmed"
id="pnpConfirmDeleteForm:deleteActionConfirmed" role="button"
aria-disabled="false">
<span class="ui-button-text">Delete</span>
</button>
<a
onclick="PrimeFaces.ab({source:'pnpConfirmDeleteForm:deleteActionConfirmedLink',process:'pnpConfirmDeleteForm:deleteActionConfirmedLink',update:'pnpEditForm pnpExistingForm',oncomplete:function(xhr,status,args){pnp_delete_confirmDialog.hide();}});return false;"
class="ui-commandlink" href="#"
id="pnpConfirmDeleteForm:deleteActionConfirmedLink">Delete</a>
<button type="button" onclick="pnp_delete_confirmDialog.hide();"
class="ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only"
name="pnpConfirmDeleteForm:deleteActionCancelled"
id="pnpConfirmDeleteForm:deleteActionCancelled" role="button"
aria-disabled="false">
<span class="ui-button-text">Cancel</span>
</button>
<input type="hidden" autocomplete="off"
value="7076449462381240234:-2976764560029615800" id="javax.faces.ViewState"
name="javax.faces.ViewState">
</form>
You can see that there is no onclick generated for the button, where there is for the link. Am I missing something or is this a bug in primefaces? If a bug, is there a workaround other than using links with styles to make them look like buttons?
I am using mojarra 2.1.14 with primefaces 3.4.2 on tomcat 6.0.32 (servlet 2.5, el 2.1).

ARGH... Simple mistake. The type attribute of the p:commandButton determines the behavior. It appears that by setting type='button' I have turned it into a (taken from the primefaces user guide):
Push Buttons
Push buttons are used to execute custom javascript
without causing an ajax/non-ajax request. To create a push button set
type as "button".
<p:commandButton type="button" value="Alert"
onclick="alert(‘Prime’)" />
Switching type to submit fixed this issue. Lesson learned... If using buttons, type='button' causes the component to ignore any server side action.

Related

Give a Style Class for Primefaces Generated span element

Primefaces password control generates a span element and an input text element when HTML is created. How can we give a class for such generated span element?
JSF Code
<p:password id="pwd"
toggleMask="true"
value="#{webUserController.password}"
class="form-control w-100" >
</p:password>
Generated HTML
<span class="ui-password ui-password-masked ui-inputwrapper ui-input-icon-right ui-inputwrapper-filled">
<input id="j_idt603:j_idt608:pwd" name="j_idt603:j_idt608:pwd" type="password" class="ui-inputfield ui-widget ui-state-default ui-corner-all form-control w-100 ui-state-filled" aria-disabled="false">
<i id="j_idt603:j_idt608:pwd_mask" class="ui-password-icon"></i>
</span>
How can I give a style class to the generated span element?
It looks like you are trying to get the field to be 100% wide. You could use PrimeFlex to do this by wrapping your p:password with <div class="field"> (p-field if you are on PrimeFlex 2), so:
<div class="field">
<p:outputLabel for="#next" .../>
<p:password .../>
</div>
See:
https://www.primefaces.org/primeflex/formlayout

Primefaces avoid submitting multiple forms

I am new to Primefaces and I am working on a requirement to open a dialog box when we click on the button.
I could able to open the dialog and submit the form. But here I am facing a new that form behind the modal dialog also get submitted when I am trying to submit the form in the modal. The form behind the modal is a pure html code and modal dialog form is written in primefaces.
Is there any chances to submit the form that is existing in the dialog and skip the form behind the dialog. Could anyone tell me the solution for this?
For clear understanding, I am submitting the code below
<form class="form-horizontal" action="${request.contextPath}/appLogin" role="form" method="POST" h:rendered="true">
<div class="form-group">
<div class="col-sm-12" align="center">
<font color="red"> <h:outputLabel
value="${SPRING_SECURITY_LAST_EXCEPTION.message}" />
</font>
</div>
</div>
<div class="form-group">
<div class="col-sm-12">
<label for="username">Username</label> <input type="text"
class="form-control" name="username" id="username"
placeholder="Enter your username" />
</div>
</div>
<div class="form-group">
<div class="col-sm-12">
<label for="pwd">Password</label> <input type="password"
class="form-control" name="password" id="password"
placeholder="Enter password" />
</div>
</div>
<div class="form-group">
<div class="col-sm-12">
<div class="row">
<div class="col-sm-6">
<input type="checkbox" name="remember" id="remember" />
<h:outputText value=" Remember Me" />
</div>
<div class="col-sm-6" align="right">
<p:commandLink value="Forgot Password?" id="loginforgotpasswordlink"
onclick="clearEmailForgotPasswordPopUp();" />
</div>
</div>
</div>
</div>
</form>
<p:dialog id="emailIdDialog" modal="true" widgetVar="emailIdDialog" width="400"
header="Email Id" appendTo="#(body)" resizable="false">
<ui:include src="/faces/validateEmailId.xhtml" />
</p:dialog>
<div class="form-group">
<p:outputLabel for="emailid1" value="Email" class="col-sm-3 control-label align-right" style="border: 0px solid green;padding-right: 0px;text-align: right;"></p:outputLabel>
<div class="col-sm-9" style="border: 0px solid red;padding-left:0px;">
<p:inputText type="text" id="emailid1"
name="emailid1" required="true" requiredMessage="Please enter an email address"
placeholder="Enter your email id" style="width:100%"/>
</div>
<p:spacer height="10px"></p:spacer>
<div class="text-right" style="padding-left: 0px;">
<p:commandButton value="Submit" update="messages,:emailIdValidation" style="float: right; margin-right: 15px;">
<f:actionListener binding="#{someClassBean.validateEmail()}" />
</p:commandButton>
</div>
</div>
</h:form>
When I am clicking the form submit button in modal dialog the other form also getting submitting.

How to open multiple component in p:inplace at once

i need to make all component editable when i clicked on h:commandLink
This my code
<p:dataTable styleClass="borderless" id="projectsTable" var="o" value="#{order.orderList}">
<p:column>
<div class="tasks">
<div class="task-item task-success">
<h:form>
<div class="task-text">
<div class="form-group">
<h:outputLabel for="projectName" value="Project Name:" />
<p:inplace effectSpeed="fast" editor="true">
<p:inputText styleClass="form-control" value="#{o.productName}" required="true" label="text" />
</p:inplace>
</div>
<div class="form-group">
<h:outputLabel for="projectURL" value="Project URL:" />
<p:inplace effectSpeed="fast" editor="true">
<p:inputText styleClass="form-control" value="#{o.price}" required="true" label="text" />
</p:inplace>
</div>
</div>
<div class="task-footer">
<div class="pull-left">
<h:commandLink >
<span class="glyphicon glyphicon-ok-circle" aria-hidden="true"></span> EDIT
</h:commandLink>
</div>
<div class="pull-right">
<h:commandLink action="#{order.deleteAction(o)}" >
<span class="glyphicon glyphicon-remove-circle" aria-hidden="true"></span> Delete
</h:commandLink>
</div>
</div>
</h:form>
</div>
</div>
that's link i need to click on it and open all h:inputText
<h:commandLink action="#{order.update(o)}">
<span class="glyphicon glyphicon-ok-circle" aria-hidden="true">
</span> EDIT
</h:commandLink>
Such as linkedIn in editProfile page when click on button appear all editable components
Examples:
Befor click button
After clicked button
First of all, every PrimeFaces component has a javascript representation which is acessible through the widgetVar.
The Inplace's widget has a method called show() that you can use to show the input field for it. Check this code out:
<p:inplace ... widgetVar="myinplace">
<p:inputText ... />
</p:inplace>
<!-- this button's click will show the input -->
<button onclick="myinplace.show()">Click Me</button>
I suggest you to set the widgetVar attribute for the inplace components and call the show method on each one of them inside a function that you can use everywhere you want:
<script>
function showInplaces() {
myinplace1.show();
myinplace2.show();
...
}
Cheers
During my lunchbreak I was curious, so I did have a quick look.
I looked at the generated source in the showcase of the first item:
<span id="j_idt88:basic" class="ui-inplace ui-hidden-container" data-widget="widget_j_idt88_basic">
<span id="j_idt88:basic_display" class="ui-inplace-display" style="display:inline">Edit Me</span>
<span id="j_idt88:basic_content" class="ui-inplace-content" style="display:none">
<input id="j_idt88:j_idt91" name="j_idt88:j_idt91" value="Edit Me" class="ui-inputfield ui-inputtext ui-widget ui-state-default ui-corner-all" role="textbox" aria-disabled="false" aria-readonly="false" type="text" />
</span>
</span>
I noticed the class='ui-inplace-display' class which is on each 'component. The following jquery code selects all inplace components that can be clicked:
$('.ui-inplace-display')
I tried this in the FireFox developer console resulting in the following output:
Object { length: 5, prevObject: Object, context: HTMLDocument → inplace.xhtml, selector: ".ui-inplace-display", 5 more… }
I know you can enable the editing by clicking on an item and so I had to find a way to click on each one. Fortunately, you can give each of them a click by just appending .click() to the selector. It will be applied to each of the components:
$('.ui-inplace-display').click()
And like mentioned, you do not need any jsf button for this, just a plain html one to execute the javascript in an onlclick:
<input onclick="$('.ui-inplace-display').click()" value="Click to edit" type="button">
works perfectly.
As you can see, it pays to learn the basics of webdevelopment before diving into using more complex frameworks since no framework ever solves all of your problems and from time to time (more often then you think), you do need a little low-level javascript

Params of button always empty even after clicking jsf

I am opening a modal which has form in it. I am trying to check if the button is clicked or not by #{empty param['buttonid']}. But it is always shows empty even when clicked.
<div class="modal fade" jsf:id="dataReset">
<div class="modal-dialog">
<form jsf:id="reset-data-form" class="form-horizontal">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title">Modal Header</h4>
</div>
<div class="modal-body">
<div class="form-group">
<label for="inputEmail" class="col-sm-3 control-label">Email</label>
<div class="col-sm-9">
<input type="text" class="form-control"
jsf:id="inputEmail" jsf:value="#{dataResetFacade.dataResetEmail}"
name="inputEmail" />
<h:message for="inputEmail" p:class="error-msg"/>
</div>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-default"
data-dismiss="modal">#{msg['general.button.cancel']}</button>
<button class="btn btn-primary" jsf:id="reset-data-button"
jsf:action="#{dataResetFacade.resetdata}">submit
<f:ajax execute="#form" render="#form aaa bbb messages" onevent="close"/>
</button>
<h:outputText id="aaa" value="#{not empty param['reset-data-button']}"/>
<h:outputText id="bbb" value="#{empty param['reset-data-button']}"/>
</div>
</div>
</form>
</div>
</div>
Am I doing some thing wrong.
You did not specify the right request parameter name there. The request parameter name is basically the JSF component's client ID. The client ID of a JSF input and button component is represented by the HTML element's name attribute. You can find it out by just looking at the JSF-generated HTML output via rightclick, View Source in webbrowser.
Given the current view, that'll look like as below:
<button name="reset-data-form:reset-data-button" ... />
Alter parameter names accordingly:
<h:outputText id="aaa" value="#{not empty param['reset-data-form:reset-data-button']}" />
<h:outputText id="bbb" value="#{empty param['reset-data-form:reset-data-button']}" />
Alternatively, just bind the JSF UIComponent instance to an unique variable name in Facelet scope using binding attribute and then let JSF evaluate the UIComponent#getClientId().
<button jsf:binding="#{resetButton}" ... />
...
<h:outputText id="aaa" value="#{not empty param[resetButton.clientId]}" />
<h:outputText id="bbb" value="#{empty param[resetButton.clientId]}" />
Note: do not bind it to a bean property. The above code is as-is.
See also:
How does the 'binding' attribute work in JSF? When and how should it be used?

Validation failed javascript callback in JSF

I have a template in which I can add a CSS error class to a div when the validation of a component has failed and it renders a pretty nice effect on the browser.
Now, I don't need to add a css class to a component (this won't help me), but rather I need to change the css of the html that surrounds it, this is pretty simple with jQuery, however I can't seem to find a javascript callback for failed validation, is this possible? I'm also using primefaces (in case they provide such capabilities).
Markup:
<div class="control-group ERROR_CLASS_GOES_HERE_IF_VALIDATION_FAILED">
<label class="control-label">Input value:</label>
<div class="controls">
<h:inputText class=" inputbox" type="text" required="true" /> <!--Component that can fail -->
</div>
</div>
if the input text is empty, I need the div that wraps the "control group" to have an extra class. I can turn it into a <h:panelGroup> so it is a JSF component but still I wouldn't know how to do it. Javascript seems easier as I can do a:
jQuery("#ID_OF_DIV").addClass("error_class")
Just let JSF/EL conditionally print the class based on FacesContext#isValidationFailed().
<div class="control-group #{facesContext.validationFailed ? 'error_class' : ''}">
You only need to ensure that this element is covered by ajax update/render.
Another way would be hooking on the oncomplete event of an arbitrary PrimeFaces ajax based component. There's an args object available in the scope which in turn has a validationFailed property. E.g. <p:commandButton oncomplete> or even <p:ajaxStatus oncomplete>.
<p:ajaxStatus ... oncomplete="if (args && args.validationFailed) $('#ID_OF_DIV').addClass('error_class')">
If you want to do everything on the client side.
<h:outputText class="samplecls" rendered="#{facesContext.validationFailed}"
value="Please enter all the required fields">
</h:outputText>
<div class="control-group ERROR_CLASS_GOES_HERE_IF_VALIDATION_FAILED">
<label class="control-label">Input value:</label>
<div class="controls">
<h:inputText class=" inputbox" type="text" required="true" /> <!--Component that can fail -->
</div>
</div>
Javascript/Jquery
This class will exist in DOM only validation fails by rendered="#{facesContext.validationFailed}"
$(window).load(function(){
if($('.samplecls').length>0){
$("#ID_OF_DIV").addClass("error_class");
}
});

Resources