JSF 2 Property does not reflect the changes after an ajax action - java

This is the situation:
I have a popup box to select one of the item listed(click the showParentAssetSearchButton) . Once selected the value of the selected item will be display in the main screen. In the main screen, there will be a button to clear up the item that selected. It will trigger an ajax action to the managed bean to clear the binding value(via click clearParentAssetButton).
When i do debugging, the value is clear and will not show in the main screen. However when i click on the save button, i notice that the property that should be empty is not actually empty. It still keep the value.
Following is the snippet UI code:
<h:panelGroup id="myregion">
<p:inputText id="parentAsset"
ondblclick="parentAssetDlg.show()"
value="#{assetMasterCreatePage.parentAsset.shortName}"
rendered="#{not empty assetMasterCreatePage.parentAsset}"/>
</h:panelGroup>
<p:commandButton icon="ui-icon-search"
id="showParentAssetSearchButton"
type="button"
title="#{msg.label_asset_search_parent_asset}"
onclick="parentAssetDlg.show()" />
<p:commandButton icon="ui-icon-trash"
id="clearParentAssetButton"
title="#{msg.label_asset_clear_parent_asset}"
actionListener="#{assetMasterCreatePage.doResetParentAsset}"
immediate="true"
process="#form"
update="clearParentAssetButton, myregion"
disabled="#{empty assetMasterCreatePage.parentAsset}" />
........
<p:commandButton value="#{msg.button_save}" icon="ui-icon-disk"
action="#{assetMasterCreatePage.doSaveAsset}" />
This is the managed bean snippet
#ManagedBean(name="assetMasterCreatePage")
#ViewScoped
public class AssetMasterCreatePage extends DefaultAssetMasterPage {
private AssetMaster assetMaster;
private AssetMaster parentAsset;
..........
.........
public void doResetParentAsset(){
parentAsset = null;
}
public String doSaveAssetMaster(){
assetMaster.setParentAsset(parentAsset);
assetMasterService.save(assetMaster);
MessageUtils.saveSuccessMessage();
return "save";
}
}
As you can see, when the button of the clearParentAssetButton is click, it will trigger ajax action #{assetMasterCreatePage.doResetParentAsset} to reset the value of the parentAsset. The issue here is when saving, the parentAsset which already should be null is not null.
I am using JSF 2 to perform the tasks.

Strange, is there any other fields which hold the value of parentAsset, I mean's in the page, have some fields like
<h:inputText value="parentAsset.shortName"/>, when you click the save button, a new parentAsset is initialized and saved, and also you can debug it and see the parentAsset's hash code to make sure whether the same one.

Related

setting h:selectBooleanCheckbox value to false prevents commandButton oncomplete from being invoked

I am new to JSF and am working with an rich:extendedDataTable where one of the columns has an h:selectBooleanCheckbox as the header for select all purposes.
At the bottom of the table there is a a4j:commandButton (delete selected button) with an oncomplete action to launch a rich:popupPanel (confirm delete panel).
This all works fine, but when the table is refreshed, the select all checkbox remains checked after a delete is performed. In an effort to have it default to false when the table has been refreshed after a delete, I tried adding value="#{false}" to the checkbox. The problem is, when this value is set, my commandButton's oncomplete no longer gets invoked and is unable to show the pop-up panel.
I don't see the connection between the two, but maybe someone has an idea? Both the commandButton and extendedDataTable are within the same h:form For the time being, I am having my pop-up panel appear by using onbegin instead.
here is the code for my select all column.:
<rich:column id="modSelectColId" label="Selected">
<f:facet name="header">
<h:selectBooleanCheckbox id="selectAllId" onclick="selectAll(this)" value="#{false}"/>
</f:facet>
<h:selectBooleanCheckbox id="selectId" value="#{myBean.selectedMap[item]}" />
</rich:column>
here is the code for my command button:
<a4j:commandButton
value="Delete Selected"
oncomplete="#{rich:component('delSelectPopupId')}.show()" />

onShow event fires unnecessarily during each page reloading

I have an issue with making a menu in my project using Primefaces. Actually, this menu will get me a possibility to show some small dialogs with settings for the workspace (by clicking on menu items). Each dialog should have data lazy loading from database. Unfortunately, when I include my dialogs in the page (single xhtml file or a couple xhtml files with ui:include), an event onShow happens on each page reload and this is wrong and provoke too many unnecessary requests to the database.
Here is an example:
UI part
<h:form id="form1">
<p:menubar id="mainMenu">
<p:submenu label="Main menu" icon="ui-icon-document">
<p:menuitem value="My settings" onclick="mySettingsWv.show()" url="#" />
</p:submenu>
</p:menubar>
</h:form>
<p:dialog id="mySettingsDlg" header="My Settings" widgetVar="mySettingsWv" resizable="false"
closable="true" modal="true" showEffect="fade" hideEffect="explode" dynamic="true"
closeOnEscape="true" onShow="#{mybean.onShow()}">
<h:outputLabel value="Settings dialog" />
</p:dialog>
ManagedBean part:
#ManagedBean (name = "mybean")
#ViewScoped
public class MyBean {
public static Logger log = Logger.getLogger(MyBean.class);
public void onShow() {
log.info("Method onShow is being called on each page reloading, but dialog still has not been shown");
}
}
If I use action "onclick" for <p:menuitem> for manual calling the necessary method, it still executes it for each page reloading. Also if I try use actionListener, action attributes it don't work. <p:ajax> cannot be attached to <p:menuitem>.
What should I do in that case? What is wrong can be in my code?
Have a look at the primefaces documentation for p:dialog (same problem with p:menuitem and onclick). There the documentation says about onShow:
Client side callback to execute when dialog is displayed. (emphasis added)
That means that you can specify a javascript function there, but it does not work that way to specify a action on your backingbean which is called everytime the dialog is shown. What happens in your case is the following: #{mybean.onShow()} is evaluated only when the file is parsed (i.e. the p:dialog is rendered into the HTML) and then the value which is returned by the method is inserted there (i.e. the empty String).
To fix this you have to define a javascript callback which makes the call on the bean. You can do this by using p:remoteCommand:
<p:remoteCommand name="onShow" action="#{mybean.onShow}"
partialSubmit="true" process="#this"/>
And then specify this callback as the onShow attribute:
<p:dialog id="mySettingsDlg" ...
onShow="onShow()">

Fire valueChangeListener with submit but after set and get methods

I have a problem I can not solve, I have a selectOneListbox with a Value Chang Listener and submit onclick. It works perfectly but the problem I have noticed is that the Set and Get methods I have for other elements in my form runs after the method that captures the ValueChangeListener. And I can not use the right data from the elements in my form, how do I resolve this?
So i got in my selectOneListbox:
<h:selectOneListbox onclick="Submit();"
valueChangeListener="#{normalbesoksgrenController.setActiveFromAllList}"
size="20" value="#{normalbesoksgrenController.currentVardTillfalleID}">
<f:selectItems itemValue="#{item.vardTillfalle.id}" itemLabel="#
{normalbesoksgrenController.getDateAndTime(item.getVardTillfalle().getStartTid())}"
var="item" value="#{normalbesoksgrenController.besokList}" ></f:selectItems>
</h:selectOneListbox>
And i got my backbean:
public void setActiveFromAllList(ValueChangeEvent event)
{
int id = Integer.parseInt(event.getNewValue().toString());
Doing some stuff..
}
I think you might want to use the ajax event like this:
<h:selectOneListBox .....>
<f:ajax execute="#form" listener="#{normalbesoksgrenController.setActiveFromAllList}" event="change" reder=":whatEverYouWant" />
</h:selectOneListBox>
The execute attribute defines what should be submitted before the ajax request is handled.

Is there a way to not sending a whole web form when click a button?

I will try to be as brief as possible, please stay with me here
"A.jsf" -> managed bean : bean
"#{bean.list}": will take us to B.jsf
<p:growl id="msgs" showDetail="true"/>
<h:form id="myform1" enctype="multipart/form-data">
<p:panel header="Upload" style="font-size: 11px;">
<h:panelGrid columns="2" cellpadding="10">
<h:outputLabel value="Drawing:" />
<p:fileUpload fileUploadListener="#{bean.handleFileUpload}" update="msgs" allowTypes="*.*;"/>
</h:panelGrid>
<p:commandButton ajax="false" immediate="true" id="back" value="Back" action="#{bean.list}"/>
<p:commandButton ajax="false" id="persist" value="Persist" action="#{bean.handleRevision}" />
</p:panel>
</h:form>
Then the handleFileUpload()
if(!upload){
FacesMessage msg = new FacesMessage(FacesMessage.SEVERITY_ERROR, "Error", "You do not have permission to upload.");
FacesContext.getCurrentInstance().addMessage(null, msg);
}
...
"B.jsf" -> managed bean: bean2
...
<p:growl id="msgs" showDetail="true"/>
...
When I click upload, it give me a growl error message "You do not have permission to upload.", which is good. But then when I click "Back", which will take me to B.jsf, I see the growl message "You do not have permission to upload." again. What seem to be happening is as I click the "Back", I send other form request to upload, which then generated the same error message, which then being displayed at B.jsf. Is there a way to fix this, beside putting the "Back" button into an empty form, because now I have two buttons standing on top of each others, instead of side by side. I try to do this:
FacesContext.getCurrentInstance().addMessage("tom", msg);
hoping that it would send to component with id="tom", so then the growl with id=msgs, would not get load, but no luck. I try to turn the upload flag on when I click the Back button, but the web form get requested before the method that handle the back navigation get called.
It is not as brief as I want it to be, therefore I want apologize for it :D
beside putting the "Back" button into an empty form, because now I have two buttons standing on top of each others
The HTML <form> is by default a block element. HTML block elements are by default been placed in a new line. You actually want to make it an inline element. You can do this using display: inline; in CSS.
Back to the actual problem, it however surprises me that the fileUploadListener method is called in spite of the immediate="true" in the p:commandButton. I tried to reproduce this and I can confirm this. But I wouldn't expect it to happen. Normally the immediate="true" on a button is the solution to skip submitting of the "whole" form (at least, skip the UIInput components without this attribute). Further investigation learnt me that the p:fileUpload isn't an UIInput component at all and that the listener is fired during apply request values phase instead of validations or update model values phase. So this behaviour is fully predictable, but imo still an oversight in the design.
Since the p:fileUpload requires ajax="false" on the p:commandButton component, you can on the other hand also just remove it from the back button so that it fires an ajaxical request and hereby skips the fileUploadListener being called.
Actually, putting the button in a different form sounds like an excellent solution. The reason the buttons don't align any more is that the new starting <form> element starts on its own line. You should be able to prevent this by adding form { display: inline; } to your CSS file.
That said, if you have some leftover error messages that you want to get rid of, you can do this in the initializing method of your backing bean (if you have one). The following works peachily:
public void clearErrorMessages() {
//it may get messy to debug why messages are swallowed
logger.debug("clearing messages, coming from " + new Exception().getStackTrace()[1]);
Iterator iter = FacesContext.getCurrentInstance().getMessages();
while (iter.hasNext()) {
FacesMessage msg = (FacesMessage) iter.next();
logger.debug("clearing message: " + msg.getDetail());
iter.remove();
}
}
The disadvantage here is that any errors that occur between submitting the form and initializing the backing bean of the target page are also swallowed.

selectOneRadio with action immediately after click

This should be easy for a pro:
I am using JSF/Facelets/Seam and am trying to display radiobuttons. Then, after the user has clicked on one of the buttons, the value should be saved and the user redirected to another page immediately (i.e. with no needed click on a submit button).
The radio button works, but not the forwarding.
Thanks
You can indeed use Richfaces to add an a4j:support component:
<h:selectOneRadio value="#{myBean.myValue}" ...>
...
<a4j:support event="onclick" action="#{myBean.doSomething}"/>
</h:selectOneRadio>
In your Java code:
public String doSomething() {
// Your code goes here...
...
// Now, we move to the new page.
return "some-outcome";
}
However, if you cannot (or do not want) to add a new library, you can do this by the old way:
<h:selectOneRadio value="#{myBean.myValue}" ... onclick="this.form.submit();" valueChangeListener="#{myBean.doSomething}">
...
</h:selectOneRadio>
This code will submit the form where the radio button are contained when the onclick Javascript event is detected. On the server side, the action doSomething will be executed.
In this method, you can make a navigation rule to be executed:
public void doSomething(ValueChangeEvent evt) {
// Your code goes here...
...
// Now, we move to another page...
FacesContext context = FacesContext.getCurrentInstance();
NavigationHandler navigation = context.getApplication().getNavigationHandler();
navigation.handleNavigation(context, "", "some-outcome");
}
where some-outcome is an outcome defined in a navigation rule in your faces-config.xml.
With JSF 2.0 you can do the following
<h:selectOneRadio ...
...
<f:ajax event="change" render="#form" />
</h:selectOneRadio>

Categories