3

Project uses Spring Webflow and JSF (PrimeFaces). I have a p:commandButton with f:attribute

<p:commandButton disabled="#{editGroupMode=='edit'}" action="edit_article_group"  actionListener="#{articleGroupManager.setSelectedRow}" ajax="false" value="Edit">    
    <f:attribute name="selectedIndex" value="${rowIndex}" /> 
</p:commandButton>

Backend code (Spring injected bean):

@Service("articleGroupManager")
public class ArticleGroupManagerImpl implements ArticleGroupManager{
    public void setSelectedRow(ActionEvent event) {
    String selectedIndex = (String)event.getComponent().getAttributes().get("selectedIndex");
    if (selectedIndex == null) {
      return;
    }
  }
}

The attribute "selectedIndex" is always null. Anybody knows what happened here? Thank you.

Raistlin
  • 407
  • 1
  • 8
  • 19
  • 1
    how about `value="#{rowIndex}"` `#` instead of `$` also instead of `setSelectedRow` rename the method into something like `updateSelectedRowValue` (dont use set/get prefix in your methods names) – Daniel Sep 19 '12 at 14:53

1 Answers1

2

The variable name "rowIndex" suggests that you've declared this inside an iterating component, such as <p:dataTable>.

This is then indeed not going to work. There's physically only one JSF component in the component tree which is reused multiple times during generating HTML output. The <f:attribute> is evaluated at the moment when the component is created (which happens only once, long before iteration!), not when the component generates HTML based on the currently iterated row. It would indeed always be null.

There are several ways to achieve your concrete functional requirement anyway. The most sane approach would be to just pass it as method argument:

<p:commandButton value="Edit" 
    action="edit_article_group"  
    actionListener="#{articleGroupManager.setSelectedRow(rowIndex)}" 
    ajax="false" disabled="#{editGroupMode=='edit'}" />  

with

public void setSelectedRow(Integer rowIndex) {
    // ...
}

See also:


Unrelated to the concrete problem, I'd in this particular case have used just a GET link with a request parameter to make the request idempotent (bookmarkable, re-executable without impact in server side, searchbot-crawlable, etc). See also Communication in JSF 2.0 - Processing GET request parameters.

Community
  • 1
  • 1
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • Shouldn't it be an `action`, not an `actionListener`? What about method signature? Even after reading all of your answers about action vs actionListener, I guess I still don't understand it completely. – RinaldoDev Sep 19 '12 at 22:33
  • @RinaldoPJr: this is indeed a corner case. This particular example basically supplants the `` (which could be used if EL 2.2 wasn't supported). Note that no business action is invoked here, just a setter is being set and navigation is been performed. – BalusC Sep 19 '12 at 23:08
  • But doesn't the method have to follow the signature (receive an `ActionEvent` as parameter, and nothing else)? – RinaldoDev Sep 20 '12 at 00:02
  • @Rinaldo: Only if you don't specify a custom argument in EL, then `ActionEvent` is required. This is more EL specific than JSF specific. If you explicitly specify an argument in EL, it get precedence. It's indeed confusing as this possible override in EL is nowhere mentioned in JSF spec itself. – BalusC Sep 20 '12 at 00:26
  • Ok, thanks for the clarification. I think it's a good topic for an article. :) – RinaldoDev Sep 20 '12 at 10:41
  • Thank you guys very much for the nice explanation and tutorial! Sorry I didn't reply because I was stuck on another problem: I got NullPointerException when calling "#{articleGroupManager.setSelectedRow(rowIndex)}". We use tomcat7 and commons-el jar. They could handle expression like "#{articleGroupManager.setSelectedRow('0')}" but not a variable as the argument. So finally I used a hidden variable to capture the rowIndex and set it by javascript. BalusC I learned a lot from your answers. You are JSF master! – Raistlin Sep 24 '12 at 12:43