1

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.

wsaxton
  • 1,030
  • 15
  • 34

1 Answers1

1

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:


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!)

Community
  • 1
  • 1
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • I will try this...I'm using Glassfish 3 so I'm almost certain it would use the latest EL version. Follow-up question: how do you, then, access the 'currentRow' variable within the 'edit' method? – wsaxton Aug 31 '11 at 18:54
  • If your `web.xml` is declared conform Servlet 3.0, then EL 2.2 will definitely work. The action method is straightforward. I added an example to the answer along with a bunch of links to related questions with more detailed examples of EL 2.2 and `DataModel` ways. – BalusC Aug 31 '11 at 18:58
  • Thanks Balus. So far so good. But I have other uses of "currentRow" throughout the Bean...not just in action methods. For example, I have an "isEditingCurrentRow" method which uses getCurrentRowBean as well. It doesn't look like you can pass a variable to this, as you can an action method. Any ideas? – wsaxton Aug 31 '11 at 19:15
  • Let the action method delegate. E.g. `this.currentRow = currentRow;` or `doSomethingWith(currentRow);`. By the way, you really didn't read the CRUD example link? :) It contains an example of triggering the "Edit mode". You can also just do `rendered="#{not empty bean.currentRow}"` to show the edit part. – BalusC Aug 31 '11 at 19:17
  • The CRUD link certainly seems very valuable...for the next time I write a CRUD application. Unfortunately, I just wanted to rewrite a little bit of my code...not all of it! I'm not sure delegation will work because every row checks isEditingCurrentRow to render differently. It compares the currentRow to the row being editing and, if they are the same, returns true (otherwise, false). So, the isEditingCurrentRow actually needs to take in a variable somehow. – wsaxton Aug 31 '11 at 19:25
  • On the other hand, perhaps I should just scrap the whole idea and use the "getBean(String beanName)" method I found on here a while ago...heck, I think you were the one that even wrote it :) – wsaxton Aug 31 '11 at 19:26
  • Perhaps I don't understand, but the "isCurrentRowEditing" method is checked on a per row basis. `rendered="#{not empty bean.currentRow}"` just checks to see if ANYTHING is being edited, not just the current row, right? I'll add the code of what it actually does to my OP. – wsaxton Aug 31 '11 at 19:35
  • You can go many ways. The key point is that you now know how to get the current row in the bean. You just do the desired postprocessing/delegating job in the action method. – BalusC Aug 31 '11 at 19:45
  • @BalusC let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/3041/discussion-between-wfsaxton-and-balusc) – wsaxton Aug 31 '11 at 19:52
  • Sorry, I decline participating in chat. I have updated the answer based on your question update. – BalusC Aug 31 '11 at 19:55
  • You're a genius! Thanks (yet again) for helping us out with our JSF woes! – wsaxton Aug 31 '11 at 20:07