I'm trying to disable a jsf component just by defining a action method and bind it to the components "disabled" attribute.
My JSF component snippet
<h:form id="bulk_sch_form1">
<a4j:commandButton id="alls" value="a. Search records form this company"
action="#{recordsTransferSearch.actionSearch}"
reRender="srtDlGrd, dlod_msg_grd, pending_student_table"
disabled="#{not recordsTransferSearch.isDisabled}">
</a4j:commandButton>
</h:form>
Backing bean action method
public boolean isDisabled() {
if (searchResults != null) {
return true;
}
return false;
}
The searchResults just evaluating after a successful search result has been returned. But as stated in the title it's not calling the action method isDisabled() at all, thus nothing happens.
The action method is only calling when I'm refreshing the page.
Thanks.
You should either use disabled as a field getter, like in disabled="#{not recordsTransferSearch.disabled}", or if your EL supports method calls, i.e. is of version 2.2+, you should add empty parentheses, (), at the end of the method call, like in disabled="#{not recordsTransferSearch.isDisabled()}".
Note that as it stands, and contrary to what you suggest in comments, disabled="#{bean.isDisabled}" will trigger Property 'isDisabled' not found error.
As per your comments you do not fully understand how disabled attribute works in JSF. It seems that you expect the button to become enabled/disabled on some javascript event and/or via some changes made by some action/actionlistener methods. This is not the case. The button is disabled/enabled only when EL expression of disabled attribute evaluates to true/false correspondingly. You may even test it: when you remove the disabled attribute of HTML input, effectively making it enabled in client side and will call that button, you'll see that no action method will be called, but instead its disabled attribute will be reevaluated on server and, as it'll evaluate to false, no method will be called.
To make it work as expected, you need to rerender the command button via AJAX call (by specifying its id in reRender attribute of another <a4j:commandButton> that changes the result of isDisabled() method so that it'll return false), or synchronously (enforcing the needed evaluation of disabled) so that the disabled condition will be evaluated to false.
Also, it would be good to go through a basic example to get a grasp of how it all works.
The view:
<h:form>
<h:commandButton id="disabled" value="Disabled command button"
action="#{bean.disabledSubmit}"
disabled="#{not bean.disabled}">
</h:commandButton>
<h:commandButton id="simple" value="Enable a disabled button"
action="#{bean.simpleSubmit}">
<f:ajax render="disabled"/>
</h:commandButton>
</h:form>
The bean:
#ManagedBean
#ViewScoped
public class Bean implements Serializable{
private boolean searchResults = false;
public boolean isDisabled() {
return searchResults;
}
public String disabledSubmit() {
return null;
}
public String simpleSubmit() {
searchResults = true;
return null;
}
}
Related
Although it is a simple question . Need an answer for this.
I have written a jsp page as :
<body>
<f:view>
<f:loadBundle basename="message" var="msg"/>
<h:form id="edit">
<h:panelGroup>
<h:selectOneRadio id="CompletePublication" layout="pageDirection">
<f:selectItem itemLabel="SUCCESS" itemValue="true"/>
<f:selectItem itemLabel="FAILED" itemValue="false"/>
</h:selectOneRadio>
</h:panelGroup>
<h:commandButton id="setAction" immediate="true" action="#{user.completePublication}" value="#{msg.Button_OK}"/>
<h:commandButton id="cancel" immediate="true" action="#{user.cancelCompletePublish}" value="#{msg.Button_CANCEL}"/>
</h:form>
</f:view>
</body>
It needs to be handled under theBean:
public class User implements Serializable {
private String name;
private boolean action;
public boolean getAction()
{
System.out.println("Get");
return action;
}
public void setAction(boolean action)
{
this.action=action;
System.out.println("Set");
}
public String completePublication(){
if (action==true){
System.out.println("Value of True Action - " + action);
return "updated";
}
if (action==false){
System.out.println("Value of False Action - " + action);
return "notupdated";
}
return null;
}
public String cancelCompletePublish()
{
System.out.println("Hi");
return null;
}
}
So can any one help on this. At the output evertime i see the "Value of False Action - False"
In your <h:selectOneRadio> you are not passing the value of the selected choice back to your bean when the form is submitted. Therefore, the action variable will never get updated. Assuming that you refer to your managed bean as user in the page, you will need to modify that component by adding the value attribute. Therefore, change
<h:selectOneRadio id="CompletePublication" layout="pageDirection">
to
<h:selectOneRadio id="CompletePublication" value="#{user.action}" layout="pageDirection">
For more information on <h:selectOneRadio> please refer to this link. Also, as mentioned by #Xtreme Biker, you need to understand what immediate="true" does when it is applied to a particular component. For your case, when a user hits any of the <h:commandButton>, the Update Model Phase (as well as other phases) will be skipped. In other words, action will never be set to true when the user selects SUCCESS and then clicks the OK (first) button. That's why you always see Value of False Action - False in your output. To fix this just remove the immediate attribute in the first <h:commandButton> like so
<h:commandButton id="setAction" action="#{user.completePublication}" value="#{msg.Button_OK}"/>
After removing that attribute, make the following change in your completePublication method
public String completePublication(){
if (action){
System.out.println("Value of True Action - " + action);
return "updated";
}
else {
System.out.println("Value of False Action - " + action);
return "notupdated";
}
}
There is no need to return null since action will either be true or false.
NOTE I intentionally did not go into detail on the behavior of the immediate attribute. If you want to understand it, you will need to spend some time to try and understand the JSF lifecycle phases. In fact, you will need to be somewhat comfortable with these concepts as you dive deeper into JSF. Both #johny and #Xtreme Biker gave you some good links to start with. I am copying them below just in case their comments get erased.
Debug JSF Lifecycle
Doubt on immediate attribute for command button
I have read a lot of posts at Stackoverflow but I didn't succeed in implementing the belowmentioned problem from my side.
the problem is: I need to type some text in <p:inputTextarea> and when clicking on button I need to get this value in the bean method.
I.e.:
<p:inputTextarea binding="#{input}"/>
<p:commandButton action="#{pessoaMB.adicionarContato(input.value)}" immediate="true"/>
with the bean method:
public void adicionarContato(String value) {
System.out.println(value);
}
The code I'm using gives me a null value.
I'm using #ViewScoped and cannot change this.
First of all, a side note: it is a bad practice to work with JSF components, you should work with model instead. I.e. don't use binding="#{input}", but stick to value="#{bean.text}".
Second, I doubt that immediate="true" is used appropriately in your setup. When used in a UICommand component like <h:commandButton> it will cause to skip JSF lifecycle for components with immediate="false" (or omitted, as it's the default), thus their value won't be set at all. Still, JSF will still preset submittedValue behind the scenes before the action method is executed.
Also, I strongly recommend to read BalusC's blog post Debug JSF lifecycle, as it is more than enlightening on the topic.
As to the solution, I'd suggest to deal with value binding with the bean, as presented in the first comment. With this approach you won't need action method parameter at all. Moreover, rethink your use of immediate attribute. If you think it's correct then you've got two choices: (1) use immediate="true" on <p:inputTextarea> or (2) switch to action="#{bean.action(input.submittedValue)}".
I would've done this :
<h:form>
<p:inputText value="#{pessoaMB.input}"/>
<p:commandButton value="add" action="#{pessoaMB.adicionarContato}" />
</h:form>
input would be here a pessoaMB property with a getter and setter (an IDE can autogenerate it).
private String input;
public String getInput() {
return input;
}
public void setInput(String input) {
this.input = input;
}
As for the adicionarContato method, it would be like this :
public void adicionarContato() {
System.out.println(input);
}
You should create a new class, i.e:
public class MyFields(){
String input1;
String input2; //and so on...
//getters and setters
}
Then, in pessoaMB create a property:
private MyFields inputFields; //getter and setter
Finally, in your xhtml file:
<h:form>
<p:inputText value="#{pessoaMB.inputFields.input1}"/>
<p:inputText value="#{pessoaMB.inputFields.input2}"/>
<!-- add more inputText components... -->
<p:commandButton value="add" action="#{pessoaMB.adicionarContato}" />
</h:form>
I have a ViewScoped ManagedBean. This bean has a boolean attribute which controls whether a datatable should be displayed. See below:
<p:dataTable value="#{loc.locationRows}" var="obj" ... rendered="#{loc.renderLocationTable}">
<p:column>
...
</p:column>
...
</p:dataTable>
My ManagedBean looks like this:
#ManagedBean(name = "loc")
#ViewScoped
public class LocationController implements Serializable {
private boolean renderLocationTable = false;
// JSF ActionListener.
public void methodA() {
if(someCondition) {
renderLocationTable = true; // this is the only time we should render location table
}
}
}
As soon as methodA() gets called and some condition is met, then the table should be rendered; and this works fine. But, the problem is this, for each and every other JSF ActionListener method which gets called, I have to explicitly set the rendered boolean back to false. See below:
#ManagedBean(name = "loc")
#ViewScoped
public class LocationController implements Serializable {
private boolean renderLocationTable = false;
// JSF ActionListener.
public void methodA() {
if(someCondition) {
renderLocationTable = true; // this is the only time we should render location table
}
}
// JSF ActionListener.
public void methodB() {
renderLocationTable = false;
}
// JSF ActionListener.
public void methodC() {
renderLocationTable = false;
}
}
I've given a very small snippet of the actual ManagedBean and XHTML file. In-reality, these files are huge and lot's of stuff is happening with several other boolean "rendered" flags. It is becoming increasingly difficult to keep these flags accurate. Plus, each ActionListener method now has to know about all boolean flags even if they are not related to the business at-hand.
This is what I'd love to be able to do:
<f:event type="postRenderView" listener="#{loc.resetRenderLocationTable}" />
<p:dataTable value="#{loc.locationRows}" var="obj" ... rendered="#{loc.renderLocationTable}">
<p:column>
...
</p:column>
...
</p:dataTable>
Then, in the ManagedBean have a method:
public void resetRenderLocationTable(ComponentSystemEvent event) {
renderLocationTable = false;
}
Wouldn't this be nice? No more playing games with resetting boolean variables. No more test cases where we need to make sure the table doesn't get displayed when it shouldn't be. The rendered flag can be set to true when the appropriate JSF ActionListener method sets it to true and then the "post-back" call will reset the flag back to false...Perfect. BUT, apparently there's no way of doing this out-of-the-box with JSF.
So, does anyone have a solution to this issue?
Thanks!
By the way, this situation happens probably a lot more than you think. Anytime you have a form with several commandButtons using ActionListeners, then this situation could happen to you. If you've ever had a JSF ManagedBean and you find yourself setting boolean flags to true or false scattered through-out the class, then this situation applies to you.
You didn't added primefaces tag, but according to your code I see that you are using Primefaces. A suppose your methodA() is called from, for example p:commandButton. I suggest first to create primefaces remote command:
<p:remoteCommand name="resetRenderLocationTable">
<f:setPropertyActionListener value="#{false}" target="#{loc.renderLocationTable}"/>
</p:remoteCommand>
this will create JavaScript function named resetRenderLocationTable whose call will generate AJAX request which will set renderLocationTable property to false. Now just add call to that function in oncomplete of you commandButton (or any other AJAX source):
<p:commandButton action="#{loc.methodA()}" update="myDatatable" oncomplete="resetRenderLocationTable()"/>
In next request you don't have to worry about resetting this property, just update your datatable.
This question already has answers here:
How to ajax-refresh dynamic include content by navigation menu? (JSF SPA)
(3 answers)
Closed 1 year ago.
I'm relatively new to JSF and trying to learn how current JSF 2 applications are designed. I've seen reference to single page applications that use ajax. Can someone fill me in on some of the techniques used and / or point me to a model or book? The books I've seen (JSF Complete Reference etc.) are good for basic tech issues but I can't find a source for current design techniques.
Thanks
Dave
In order to implement your Single Page Application, you should state which piece of your page should be rendered. This can be accomplished making use of a boolean flag such as create, edit, list, and so on. For instance, see the following (Just relevant code)
<h:body>
<h:form rendered="#{userController.stateManager.create}">
<h:panelGroup rendered="#{not empty facesContext.messageList or userController.stateManager.failure}">
<!--render error message right here-->
</h:panelGroup>
<div>
<label>#{messages['br.com.spa.domain.model.User.name']}</label>
<h:inputText value="#{user.name}"/>
</div>
<h:commandButton action="#{userController.create}">
<f:ajax execute="#form" render="#all"/>
<f:actionListener type="br.com.spa.web.faces.listener.StateManagerActionListener" />
<f:setPropertyActionListener target="#{userController.stateManager.create}" value="true"/>
<f:setPropertyActionListener target="#{userController.user}" value="#{user}" />
</h:commandButton>
</form>
</h:body>
Notice that our form will be rendered when a flag create is true - See second line above. To wrap our flags, we create a classe named StateManager as follows
/**
* I am using lombok, which takes care of generating our getters and setters. For more info, please refer http://projectlombok.org/features/index.html
*/
#Setter #Getter
public class StateManager {
private boolean create;
private boolean edit;
private boolean list;
}
Now, because we are using only a single page, we should use a ViewScoped managed bean, which keep our managed bean scoped active as long as you are on the same view - Is it a single page application, right ? So, no navigation. With this in mind, let's create our managed bean.
#ManagedBean
#ViewScoped
public class UserController implements StateManagerAwareManagedBean {
private #Inject UserService service;
private #Getter #Setter stateManager = new StateManager();
private #Getter #Setter List<User> userList = new ArrayList<User>();
private #Getter #Setter User user;
#PostConstruct
public void initialize() {
list();
}
public void create() {
service.persist(user);
stateManager.setCreate(false);
stateManager.setList(true);
stateManager.setSuccess(true);
}
public void edit() {
service.merge(user);
stateManager.setEdit(false);
stateManager.setList(true);
stateManager.setSuccess(true);
}
public void list() {
userList = service.list();
stateManager.setList(true);
}
}
For each action method, we define which piece of our page should be rendered. For instance, consider that our form was processed, covering all of JSF lyfecycle, which implies that their values was successfully converted and validated, and our action method invoked. By using as example our create action method - see above -, we set its create flag as false because our form was converted and validated, so we do not need to show it again (Unless you want). Furthermore, we set both list and success flag as true, which indicates that the list of our page should be rendered and our form was successfully processed - You could use this flag to show something like "User created" such as bellow
<h:panelGroup rendered="#{userController.stateManager.success}">
#{messages['default.created.message']}
</h:panelGroup>
Now, let's discuss which piece of our page should be rendered when it is called for the first time. Maybe you do not know but a void method annotated with #PostConstruct will be called first. So we define which piece of our page should be rendered. In our example, we call list method, which sets its list flag as true and populate a backing list.
#PostConstruct
public void initialize() {
list();
}
Finally, let's review the following order nested within h:commandButton
<h:commandButton action="#{userController.create}">
<f:ajax execute="#form" render="#all"/>
<f:actionListener type="br.com.spa.web.faces.listener.StateManagerActionListener" />
<f:setPropertyActionListener target="#{userController.stateManager.create}" value="true"/>
<f:setPropertyActionListener target="#{userController.user}" value="#{user}" />
</h:commandButton>
First of all, you should call an ActionListener - here called StateManagerActionListener - which takes care of resetting any StateManager - code bellow. It must be called first before any other setPropertyActionListener designed to control any flag because the order defined within h:commandButton is the order in which they will be called. keep this in mind.
public class StateManagerActionListener implements ActionListener {
public void processAction(ActionEvent e) throws AbortProcessingException {
Map<String,Object> viewMap = FacesContext.getCurrentInstance().getViewRoot().getViewMap();
for(Map.Entry<String,Object> entry: viewMap.entrySet()) {
if(entry.getValue() instanceof StateManagerAwareManagedBean) {
((StateManagerAwareManagedBean) entry.getValue()).setStateManager(new StateManager());
}
}
}
}
StateManagerAwareManagedBean - used in our ViewScoped Managed bean -, which allows that we reset any StateManager of any ManagedBean instead of resetting one by one in our ActionListener, is defined as follows
public interface StateManagerAwareManagedBean {
StateManager getStateManager();
void setStateManager(StateManager stateManager);
}
Second, after defining our ActionListener, we use a setPropertyActionListener which set the flag which controls the enclosing piece of the view as true. It is needed because our form is supposed to be not converted and validated. So, in our action method, we set this flag as false as discussed before.
A couple of notes
User is marked as a RequestScoped ManagedBean so that it can not be injected into a ViewScoped one using a ManagedProperty because its scope is shother. To overcome this issue, i set its value by using a <f:setPropertyActionListener target="#{userController.user}" value="#{user}"> - See our form
Our example use JEE features which need a proper Application Server. For more info, refer http://docs.oracle.com/javaee/6/tutorial/doc/
ManagedBean can play different roles such as a Controller, DTO and so on. When it play a role of a Controller, i prefer suffix its name with Controller. For more info, refer http://java.dzone.com/articles/making-distinctions-between
JSF view code:
<f:view>
<h:form>
<h:panelGrid>
<h:inputText id="key" value="#{myManagedBean.key}"/>
<h:selectBooleanCheckbox id="rerun" value="#{myManagedBean.rerun}" rendered="#{myManagedBean.displayRerun}"/>
<h:commandButton id="check" action="#{myManagedBean.check}"/>
</h:panelGrid>
</h:form>
<f:view>
JSF model code:
public class MyManagedBean {
private boolean displayRerun;
public void setDisplayRerun(boolean aDisplayRerun) {
this.displayRerun = aDisplayRerun }
public boolean getDisplayRerun() {
return this.displayRerun;
}
private String key;
public void setKey(String aKey) {
this.key = aKey
}
public String getKey() {
return this.key;
}
private boolean rerun;
public void setRerun(boolean arerun) {
this.rerun = arerun
}
public boolean getRerun() {
return this.rerun;
}
public String check() {
//do data validation
setDisplayRerun(true);
System.out.println(getRerun());
}
}
This always prints false regardless of whether the checkbox is checked or not.
Additional Information on my requirement:
Nick/BalusC, my managed bean is of request scope. It is indeed simplified code snippet that I presented. My page has couple of user input controls along with a command button. On submit of command button, I call action method of backing bean, in which I do data validation (in this case I lookup database and see if the inputs are already registered.) If already registered, I come back to the same page, this is when I display the singleBooleanCheckBox for the user to select and hit the command button again.
I am toggling the display of the checkbox based on a managedbean property (a boolean flag set during data validation).
When I re-submit the page with checkbox checked, I do not receive this data.
For further verification, I replace the selectBooleanCheckbox, with a command button with similar behavior (basically do not render it initially, but only show it on data validation). I mapped its #action to my managedbean's action method. To my surprise, when I hit the button, the action method is not executed. Instead, the page is refreshed like in a "immediate" scenario or a redirect.
I have been struggling on this for almost 6 hrs. Appreciate your experienced insights.
Thanks.
So, you've actually a rendered attribute on the checkbox (that was not present in your initial question) and the bean is request scoped (it would have worked when it was session scoped). The submitted checkbox value will not be gathered during apply request values phase when this attribtue evaluates false at that point.
You basically need to retain the condition responsible for the rendered attribute in the subsequent request as well. This can be done in several ways: putting bean in session scope, using Tomahawk's t:saveState or h:inputHidden with a bean binding. Each is outlined in detail in this answer.