p:commandButton doesn't execute action function - jsf

I have a p:commnandButton as follows
<p:commandButton id="previouscat"
value="Go to #{categoryBean.getPreviousCategory().name}"
style="margin:0px;" icon="ui-icon-back" update="#all"
action="#{categoryBean.selectPreviousCat}"/>
which is inside a form. Now my problem is that when clicking on the button, the action doesn't execute cause then it should change the value of the button. I've tryed with setting the action function like categoryBean.selectPreviousCat & categoryBean.selectPreviousCat() with no success.
public void selectPreviousCat(){
this.selectedCategory = this.getPreviousCategory();
}

Related

p:fileUpload - Validate form prior to upload

I would like to be able to trigger validation on my form prior to being allowed to select the files for upload when clicking on the "Choose" button of the fileUpload control in Primefaces. Is this possible? At present the user can click on "Choose" and "Upload" without validation kicking in. This is preventing my document from saving but the attachments are being created.
I know I could hide the fileUpload control until the form is successfully validated and saved but I would prefer to invoke validation when you click the "Choose" button if possible.
I've tried remoteCommand calls in the onStart but can't seem to get anything to force validation to occur.
It is possible to trigger form validation when p:fileUpload Choose button is clicked by combining Java Script and p:remoteCommand.
BASIC CONCEPT
intercept Choose button click event, prevent default outcome (opening of file chooser dialog) and run p:remoteCommand instead,
when p:remoteCommand completes, and if validation is OK, do not prevent Choose button clicks any more until some data on form input elements is changed again.
PROOF OF CONCEPT EXAMPLE CODE
Add this Java script in your page
<script>
var triggerValidation;
window.onload = function () {
//initially (after page is loaded) trigger validation on Choose btn click
triggerValidation = true;
//define button click listener
registerChooseBtnClick();
};
function registerChooseBtnClick() {
//var chooseBtn = document.getElementsByClassName("ui-fileupload-choose")[0];
// or if you define p:upload widgetVar you can use PF function
var chooseBtn = PF('fileUploadWidget').chooseButton[0];
chooseBtn.addEventListener('click', fnRef, false);
}
var fnRef = function (event) {
console.log("Button clicked");
if (triggerValidation) {
//prevent file browser to open
event.preventDefault();
//trigger validation via p:remoteCommand;
submitSelection();
} else {
//File browser will be opened at this point
}
};
function checkIfValidationFailed(xhr, status, args) {
if (args) {
if (args.validationFailed) {
console.log("Validation failed");
triggerValidation = true;
} else {
triggerValidation = false;
}
}
}
//call each time when form input elements (inputText, ...) change value
function forceValidation(){
triggerValidation = true;
}
</script>
and add p:remoteCommand
<p:remoteCommand
name="submitSelection" process="#form"
oncomplete="checkIfValidationFailed(xhr, status, args)" resetValues="true"/>
Also here is xhtml page for quick testing
<h:form id="form">
<p:messages autoUpdate="true"/>
<p:panelGrid columns="1">
<!--size is integer variable-->
<p:inputText id="size" maxlength="3"
value="#{yourBean.size}"
required="true" requiredMessage="Size is missing"
onchange="forceValidation();"/>
<p:fileUpload
id="upload"
widgetVar="fileUploadWidget"
fileUploadListener="#{yourBean.onUpload}"
multiple="true"
allowTypes="/(\.|\/)(jpg|png)$/" />
</p:panelGrid>
<p:remoteCommand
name="submitSelection" process="#form"
oncomplete="checkIfValidationFailed(xhr, status, args)" resetValues="true"/>
<p:commandButton
id="submitBtn" value="Sumbit" process="#form"
actionListener="#{yourBean.onSubmit()}"/>
</h:form>

p:button with onclick javascript hook

I'm using p:button with onclick action. (I can't move to p:commandButton, because of legacy outcome navigation in faces-config.xml and custom navigation history in db):
<p:remoteCommand name="unlock_tt" actionListener="#{ttEntityMBean.unlock()}"/>
<p:button value="#{msgs['button.ok']}" outcome="#{ttEntityMBean.navigationMenuItemToRedirect.navigationRule}" onclick="unlock_tt()"/>
Generated by primefaces javascript looks like
onclick="unlock_tt(); window.open(....)"
And after clicking button, unlock_tt() in browser initiated, but immediatly broken by page redirecting, so backed java method didn't execute.
Should I make unlock_tt() or java call async to be sure it will be executed before browser leaves page?
Upd: I'm thinking to use p:commandButton, if it is possible to get to-view-id programically, like in this question:
Programmatically get navigation case <to-view-id> from faces-config.xml by outcome
<p:commandButton action="#{ttEntityBean.unlock()}"/>
public String unlock() {
//some business logic
return OutcomeResolverHelper.getRuleFor(navigationMenuItemToRedirect.navigationRule)
}
This should reduce number of requests
I'm not sure this will work but can you try this :
Instead of :
<p:remoteCommand name="unlock_tt" actionListener="#{ttEntityMBean.unlock()}"/>
<p:button value="#{msgs['button.ok']}" outcome="#{ttEntityMBean.navigationMenuItemToRedirect.navigationRule}" onclick="unlock_tt()"/>
do:
<h:panelGroup>
<f:ajax event="click" listener="#{ttEntityMBean.unlock}"/>
<p:button value="#{msgs['button.ok']}" outcome="#{ttEntityMBean.navigationMenuItemToRedirect.navigationRule}" />
<h:panelGroup>
Don't forget to remove onclick and your remotecommand.
This should wrap a panelGroup around your button. PanelGroup implements ClientBehaviorHolder so it can get f:ajax tag in its children. Thus when you click on it it should trigger the listener.
The easiest way was migration from p:button to p:commandButton, which allows to execute some java-code in action method before redirect. The core is programmical translation of navigation rule, defined in faces-config.xml to base url, usable in explisit jsf-2.0 style:
//receive base url from <to-view-id> tag
public static String resolveOutcomeRule(String ruleName) {
FacesContext context = FacesContext.getCurrentInstance();
ConfigurableNavigationHandler configNavHandler = (ConfigurableNavigationHandler)context.getApplication().getNavigationHandler();
NavigationCase navCase = configNavHandler.getNavigationCase(context, null, ruleName);
return navCase.getToViewId(context);
}
//decorate it with faces-redirect=true and our custom navigation
public static String resolveOutcome(NavigationMenuItem item) {
return resolveOutcomeRule(item.getNavigationRule()) + "?faces-redirect=true&menu=" + item.getId();
}
//controller-method
public String cancelEditTT() {
super.unlock();
return FacesUtil.resolveOutcome(getNavigationMenuItemToRedirect());
}
//new jsf button:
<p:commandButton value="#{msgs['button.ok']}" action="#{ttEntityMBean.cancelEditTT}"/>
This solution provided 1-step redirect instead of 2-step old one.

Primefaces refreshing dataTable on modal dialog commandButton click

I have dataTable for editing users.
I have commandLink in each row for opening modal dialog with selected user data for editing.
On that dialog I have commandButton for saving user.
I have a problem refreshing dataTable and displaying new edited values for user.
<p:commandButton value="Save" action="#{usersBean.updateUser()}" onclick="PF('editUserDlg').hide();" update=":adminForm:adminTabView:usersDataTable" styleClass="ui-priority-primary" style="float: right;" />
I followed BalusC answer on subject finding out id of component and have no errors in server log.
When I click on Save button I call backing bean method:
public void updateUser() {
int userId = selectedUserView.getId();
User user = adminSessionBean.getMe(userId);
try {
updateUser(user);
LOG.info("User seccessfully updated.");
} catch (Exception exc) {
String message = "Error updating user: " + exc.getMessage();
LOG.error(message);
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, message, null));
}
}
and edited user is saved correctly (I've checked in database). Problem is that I don't see new edited user values in dataTable after modal dialog is closed.
When I refresh page I see new values for user.
When I add call #PostConstruct init() method after updateUser(user); I see the changed values in dataTable, but I am not sure if this is the correct approach.
Thanks Kukeltje,
I'll go with calling init() after updateUser() method.
I wouldn't call the init method, this method should only be called after the bean is constructed as the annotation states.
Try calling a remoteCommand instead of closing your dialog directly which refreshes the dataTable. After that you could close the dialog from that command. Something like this.
<p:remoteCommand name="updateContent" update="table"
oncomplete="PF('dialog').hide();" />
Didn't tried this solution directly, but I think that should work. I used this approach for a similar problem.
EDIT: As Kukeltje states, you also have to refresh your dataModel so that the dataTable receives the new data. You could add an actionListener to the remoteCommand to do that.

Call an action listener via ajax when user presses enter on a h:form input field

I have this form
<h:form id="formId" prependId="false">
Descrizione <h:inputTextvalue="#{bean.description}" />
Prezzo: <h:inputText value="#{optionalManaged.price}" />
<a4j:commandLink styleClass="button smallButton" actionListener="#{bean.method}"
execute="formId" render="otherDiv">
+
</a4j:commandLink>
</h:form>
At the moment, pressing the a4j:commandLink stores the two input filelds' values inside my bean and calls my action listener correctly.
What I'd like to happen is that pressing enter on the second inputText does the same.
I made a naive try by calling the a4j:commandLink click() via jquery from inside the inputText. This, obviously, didn't work.
Any idea on how I could do this?
You need to detect if Enter key was pressed and click the command link programmatically. Just don't forget to set its id, as well as id of input component. The piece of JavaScript you need to add when the page has finished loading is:
document.getElementById('input').onkeypress = function(e) {
var event = e || window.event;
var code = event.which || event.keyCode;
if (code == 13) {
document.getElementById('link').click();
return false;
}
}

how to stop calling onclick function while refreshing a page?

I have a page with a p:Menuitem using OnClick function.
My problem is that when i refresh the page, the event onclick is still running, how can i stop it?
Client-side code:
<p:submenu label="Ordres de Fabrication" styleClass="submenustyle" >
<p:submenu label="Ordre non Réalisé">
<p:menuitem value="Afficher" outcome="/admin/gestionduplanning/ofnonrealiseAfficher.xhtml" onclick="#{ofrealiser.getofnonrealiser()}" />
<p:menuitem value="Ajouter" outcome="/admin/gestionduplanning/ofnorealiseAjouter.xhtml" />
</p:submenu> ...
UPDATE 1 :
<p:menuitem value="Afficher" outcome="/admin/gestionduplanning/ofnonrealiseAfficher.xhtml" onclick="#{ofrealiser.getofnonrealiser()}" actionListener="#{exporterPlanningGlobal.refreshfromjsfdateplanning()}" />
the managed bean methode :
public void refreshfromjsfdateplanning()
{
System.out.println("Test actionlistener");
}
but the methode isnt called because in my IDE glassfish it didnt print anything .
how to get the actionlistner working ??
UPDATE 2 :
i found that when i remove the outcome from the menu the action listner is working .. but when i use outcome or url to go to a page didnt work how to solve that ?
Both onclick and oncomplete should only be used to call a javascript event handler.
If you want to call something on server when clicking a menu item then use actionListener.
As a side line, of course the code inside the onclick will trigger when refreshing the page because the jsf expressions are evaluated on the page rendering phase.
You can find a working example on the Primefaces Demo
I found the solution for my problem : do a treatment before navigating with p:menuitem :
<p:menuitem value="Exporter tous les plannings" styleClass="submenustyle" action="#{exporterPlanningGlobal.refreshfromjsfdateplanning}" update="#form"/>
and managed bean methode :
public String refreshfromjsfdateplanning()
{
System.out.println("treatment done");
return "/espaceZP01/gestionduplanning/exporterTousPlanning.xhtml?faces-redirect=true";
}

Resources