I have a view-scoped bean ManageFoo.java:
#ManagedBean(name = "ManageFoo")
#ViewScoped
public class ManageFoo {
#ManagedProperty(value = "#{currentRow}")
private Foo currentRowBean;
.
.
public void setCurrentRowBean(Foo foo) {...}
public Foo getCureentRowBean() {...}
public void edit(ActionEvent e) {
getCurrentRowBean();
.
.
}
}
I then have the facelets file ManageFoo.xhtml:
<h:dataTable value=#{ManageFoo.foos} var="currentRow">
<h:column>
<h:commandLink actionListener="#{ManageFoo.edit}"/>
.
.
When the 'commandLink' is clicked, however, 'getCurrentRowBean' returns null.
I have this working fine using FacesContext and a getBean("currentRow") helper method, but I'm trying to "JSF 2ify" my web application by using ManagedProperty's, ManagedBean's, etc. Am I just not implementing this properly or am I trying to use ManageProperty's in a way that doesn't make sense?
After feedback from Balus, his solution works well for my action methods, but I'm having trouble getting it to work for methods that return values (such as boolean). The following method is used in a bunch of "rendered" attributes for each row. For example, if you are editing a certain row, all of the other edit buttons on the other rows disappear and the edit button for the current row is replaced by a cancel edit button and save button. So, this method has different return results for each row:
public boolean isCurrentRowEditing() {
if(getCurrentRowDataBean().equals(getCurrentDataEditing())) {
return true;
} else {
return false;
}
}
Since I'm trying to eliminate the "getCurrentRowDataBean()" method everywhere, I need a way for this to work.
The #ManagedProperty is set directly after bean's construction. At the point the bean is been constructed, JSF is definitely not busy iterating over the datatable. Also, your bean is put in view scope, so it's been set when the view is requested for the first time, not when you submit the form to the same view. The #{currentRow} will always be null.
There are several ways to achieve this. If you're running an EL 2.2 capable container or are using JBoss EL, then you could just pass it to the action (not listener!) method:
<h:commandLink action="#{manageFoo.edit(currentRow)}"/>
(note that I fixed your managed bean name to start with lowercase, conform the coding conventions)
with
public void edit(Foo currentRow) {
// ...
}
If you aren't running an EL 2.2 capable container nor can't use JBoss EL, then you need to bind the datatable's value to DataModel and use DateModel#getRowData() inside the action(listener) method to obtain the current row.
See also:
How can I pass selected row to commandLink inside dataTable? (shows all possible ways)
Recommended JSF 2.0 CRUD frameworks (shows DataModel way)
Update backing bean in datatable from h:commandButton and JPA (shows EL 2.2 way)
Update as per your update, just compare it in EL. E.g.
rendered="#{currentRow == manageFoo.currentRow}"
and
rendered="#{currentRow != manageFoo.currentRow}"
(note that this only works if its equals() is properly implemented!)
Related
I am trying to create a dynamic panel (panel with various items) then i want to bind it with panel component in view page, the scope of managed bean which has the panel object is #ViewScoped.
I noticed that any ajax render this panel in the view page rebuild the managed bean, Why is that ?
Here is my code :
this is the managed bean :
package test;
import org.icefaces.ace.component.panel.Panel;
#ManagedBean(name = "myBean")
#ViewScoped
public class myBean {
private Panel myPanel;
// Constructor
public myBean() {
myPanel = drawPanel(); // this function initiate and add items to the panel
}
// Setters and Getters Methods
}
and this the view page :
<h:form>
<ace:panel binding="#{myBean.myPanel}"></ace:panel>
<ace:pushButton actionListener="#{myBean.something}">
<ace:ajax render="#form" />
</ace:pushButton>
</h:form>
in every time i pressed the button, the managed bean constructor invoked , Why does that happened ?
Also i noticed that if i remove the binding attribute from the panel component or make the scope of the managed bean session or application scope, the constructor didn't invoked.
Note : I am using icefaces 3 and jsf 2.0 .
Is there any solution for this situation ?
As the ICEFaces documentation says:
The Push Button is a component that allows entry of a complete form or just itself. It has the same functionality of a regular jsf command button but without having to add extra attributes.
Because the PushButton is a command button it do navigation. If you don't use its action attribute it will apply its default value. I can't find what it is (I just suspect that it is an empty string).
The JSF navigation rules depending on the action outcome of UICommands:
null or void : reloads the current view
empty string : recreates the current view (if the view recreated, the view scoped beans do the same)
non empty string : the next view determined by the navigation handler.
If the reason is the empty string default result of the action attribute, then use it in the facet:
<ace:pushButton action="#{myBean.nextPage}" actionListener="#{myBean.something}">
And pass back a null value in its linked handler method:
public class MyBean // You use myBean here in your question improperly
{
public String nexPage()
{ return null; }
}
I try to add a object to a LinkedList in a #ConversationScoped backing bean.
#Named
#ConversationScoped
public class CategoryController implements Serializable{
...
private List<Category> selectedCategories = new LinkedList<Category>();
...
#PostConstruct
public void initNewMember() {
conversation.begin();
newCategory = new Category();
loadExistingCategories();
}
...
}
I want to send an ajax request with new objects (of type category). They should simply be added to the linked list.
this.selectedCategories.add(newParentCategory);
With the ajax render attribute <f:ajax render="allSelectedCategories"/> I immediately render the output text to render the object list.
<h:outputText id="allSelectedCategories" value="#{categoryController.selectedCategories}" />
And yes, the object I clicked is displayed, but the previously clicked objects are gone.
The values do not serialize/persist in memory during my "conversation". What do I need to do to make that conversion scope temporarily persist the values of the ajax calls?
I really want to get used to CDI and abandon the ManagedBean path for this project (e.g. #ViewScoped), despite the fact that it works like a charm.
Also, I cannot reproduce the following tutorial on CDI Conversation Scope. I simply cannot debug into the initConversation by adding
<f:event listener="#{categoryController.initConversation}"
type="preRenderView"></f:event>
I have a jsf page with multiple radiobutton groups (dynamically generated) on it. I need to retrieve the values from it in a backing bean, but fails to do so.
The business: a user wants to subscribe to a course that consists of multiple groups of coursedays. The user can choose the coursedays. So if a course consists of for example 4 coursedays, organised in 3 different groups, the user can choose from 12 coursedays, in blocks of 3.
The relevant part of the xhtml-page:
<c:forEach var="cd1" items="#{coursedayBean.getCoursedays(groupBean.getFirstGroup}">
<h:selectOneRadio value="#{subscriptionBean.selectedCoursedays[cd1.sequenceNr]}" >
<f:selectItems value="#{coursedayBean.getCoursedaysSelectItems}"/>
</h:selectOneRadio>
</c:forEach>
This results in a n*m matrix of radiobuttons where I want to retrieve n values.
The selectItems are of type <Long, String>.
In my backing bean, I declared the following:
public List<String> getSelectedCoursedays() {
return selectedCoursedays;
}
public void setSelectedCoursedays(List<String> selectedCoursedays) {
this.selectedCoursedays = selectedCoursedays;
}
I tried with a Map, List, but none of them worked. The setSelectedCoursedays is never called.
How do I declare the array/list/map to get the values in my backing bean?
#{subscriptionBean.selectedCoursedays[cd1.sequenceNr]}
doesn't do the trick.
This construct should work just fine. The setter will indeed never be called. JSF/EL just calls the setter on ArrayList itself by the add(index, object) method. I.e. it does basically:
subscriptionBean.getSelectedCoursedays().add(cd1.sequenceNr, selectedItem);
I'm not sure how you observed the concrete problem of "it doesn't work". Perhaps you were firing an ajax request and putting a breakpoint on the setter method and didn't read the server logs. There are two possible cases where this construct will fail.
If you don't prepare the selectedCoursedays with new ArrayList(), then you will get PropertyNotFoundException: Target Unreachable, 'selectedCoursedays' returned null.
If you don't fill the selectedCoursedays with the same amount of null items as the course days, then you will get an ArrayIndexOutOfBoundsException
So, you should prepare the selectedCoursedays as follows:
#PostConstruct
public void init() {
selectedCoursedays = new ArrayList<String>();
for (int i = 0; i < coursedays.size(); i++) {
selectedCoursedays.add(null);
}
}
Easier alternative is to make it a String[].
private String[] selectedCoursedays;
#PostConstruct
public void init() {
selectedCoursedays = new String[coursedays.size()];
}
It is miss understanding between c:forEach and ui:repeat. c:forEach will not build UI component tree nodes. Firstly, you have to reference difference between them here.
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.
I created a simple HtmlInputText
<h:inputText binding="#{IndexBean.objUIInput}" />
Then in my managed bean, it is :-
private UIInput objUIInput;
public UIInput getObjUIInput() {
objUIInput.setValue("laala");
return objUIInput;
}
public void setObjUIInput(UIInput objUIInput) {
System.out.println("Set!!");
this.objUIInput = objUIInput;
}
But i always get NullpointerException. Do i need to do anything extra on my JSF page? like we do jsp:usebean setproperty? Please help me.
Whenever you'd like to change the component's default state/behaviour prior to display, then you need to instantiate it yourself. I.e. during declaration:
private UIInput objUIInput = new HtmlInputText();
or during construction:
public Bean() {
this.objUIInput = new HtmlInputText();
}
or, as Bozho suggested, using #PostConstruct:
#PostConstruct
public void init() {
this.objUIInput = new HtmlInputText();
}
(which will take place after construction of the bean and initialization/setting of all managed properties).
And indeed, you should preferably not do any business logic in getters/setters. They are to be used to access bean properties and they can be called more than once during bean's life.
As per the comments, you can alternatively also move the UIInput#setValue() call to the setter method. JSF will call it once directly after precreating the component.
public void setObjUIInput(UIInput objUIInput) {
this.objUIInput = objUIInput;
this.objUIInput.setValue("laala");
}
When you bind a component, the getter and setter are supposed to be simple - only get/set - no logic inside them.
Perhaps the JSF lifecycle is calling the getter to check whether it needs to instantiate the component, and the getter initially would throw a NPE.
Remove all logic from your getter, or at least add a null check.
Actually, I'd advice for not using binding at all.
If you want to set an initial value to your component, use a method annotated with #PostConstruct and assign the value there, then use the value attribute.