【问题标题】:JSF/PrimeFaces: programmatic <f:setPropertyActionListener> on <p:commandButton> not firingJSF/PrimeFaces:<p:commandButton> 上的编程 <f:setPropertyActionListener> 未触发
【发布时间】:2013-06-24 23:10:21
【问题描述】:

我们有一个要求,允许用户配置所有数据表中列的顺序,包括上面有操作按钮的列,这里是p:commandButtons。

因此,我们对必须手动实例化的所有列使用绑定。对于仅显示一些字符串、布尔值、日期和数字的所有列都可以正常工作,但是将p:commandButtons 添加到具有一个或多个&lt;f:setPropertyActionListener&gt;s 的列时就会出现问题。

    ELContext elContext = FacesContext.getCurrentInstance().getELContext();
    ExpressionFactory factory = FacesContext.getCurrentInstance().getApplication().getExpressionFactory();

    CommandButton button = new CommandButton();
    button.setIcon( "ui-icon ui-icon-pencil" );
    button.setProcess( "@this" );
    button.setUpdate( ":compliance-case-dialog :compliance-case-form:data" );
    button.setOncomplete( "complianceCaseDialog.show();" );

    ValueExpression targetExpression = factory.createValueExpression( elContext, "#{complianceCaseManager.selectedComplianceCaseWithRefresh}", ComplianceCase.class );
    ValueExpression valueExpression = factory.createValueExpression( elContext, "#{coca}", ComplianceCase.class );

    button.addActionListener( new SetPropertyActionListenerImpl( targetExpression, valueExpression ) );

    column.getChildren().add( button ); // add to Column instance

此按钮“正确”显示&lt;p:dialog&gt;,但应在显示对话框之前使用数据表的当前实体(由var="coca" 定义)调用ComplianceCaseManager 类的setSelectedComplianceCaseWithRefresh( ComplianceCase selectedComplianceCase ) 方法。

<p:dataTable id="data"
             widgetVar="resultTable"
             value="#{complianceCaseManager.complianceCases}"
             var="coca"
             ...>
</p:dataTable>

调试显示setSelectedComplianceCaseWithRefresh( ComplianceCase selectedComplianceCase ) 方法从未被调用。

问:

怎么了?你如何解决这个问题?

PS:配置是 PrimeFaces 3.4.2、Mojarra 2.1.22、GlassFish 3.1.2.2、Java 7


更新 1:

这是我想翻译成程序化的 p:commandButton:

<p:commandButton icon="ui-icon ui-icon-pencil"
                 title="#{msg['complianceCaseManager.data.edit.button.hint']}"
                 process="@this"
                 update=":compliance-case-dialog :compliance-case-form:data"
                 oncomplete="complianceCaseDialog.show();">
    <p:resetInput target=":unlocked-form" />
    <f:setPropertyActionListener target="#{complianceCaseManager.selectedComplianceCaseWithRefresh}" value="#{coca}" />
    <f:setPropertyActionListener target="#{complianceCaseManager.mode}" value="EDIT" />
</p:commandButton>

线

    <f:setPropertyActionListener target="#{complianceCaseManager.selectedComplianceCaseWithRefresh}" value="#{coca}" />

是我必须去工作的那个。

kolossus 创建MethodExpressionActionListener 的解决方案不适用于我的代码:

    String targetExpressionString = "#{complianceCaseManager.selectedComplianceCaseWithRefresh}";
    String valueExpressionString = "#{coca}";

    MethodExpression targetMethodExpression = factory.createMethodExpression( elContext, targetExpressionString, null, new Class<?>[]{ ComplianceCase.class } );
    MethodExpression valueMethodExpression = factory.createMethodExpression( elContext, valueExpressionString, ComplianceCase.class, new Class<?>[0] );

    button.addActionListener( new MethodExpressionActionListener( targetMethodExpression, valueMethodExpression ) );

AFAIK 是为了在目标上调用 setter 并在值上调用 setter,所以我假设 ValueExpressions 就足够了。


更新 2:

尝试通过 EL 2.2 方法调用设置当前实体也不起作用。

代码:

    String methodExpressionString = "#" + "{complianceCaseManager.selectedComplianceCaseWithRefresh(coca)}";
    MethodExpression methodExpression = factory.createMethodExpression( elContext, methodExpressionString, null, new Class<?>[]{ ComplianceCase.class } );

    button.addActionListener( new MethodExpressionActionListener( methodExpression ) );

什么都没有调用。


更新 3:

这是正确的&lt;:setPropertyActionListener&gt; 代码:

    // traditional <f:setPropertyActionListener target="#{complianceCaseManager.selectedComplianceCaseWithRefresh}" value="#{coca}" />
    ValueExpression targetExpression = factory.createValueExpression( elContext, "#{complianceCaseManager.selectedComplianceCaseWithRefresh}", ComplianceCase.class );
    ValueExpression valueExpression = factory.createValueExpression( elContext, "#{coca}", ComplianceCase.class );

    button.addActionListener( new SetPropertyActionListenerImpl( targetExpression, valueExpression ) );

非常感谢 kolossus。在实例化 PrimeFaces CommandButton 时记得调用 setId()。

【问题讨论】:

  • 您是否设置了id 属性?
  • 天啊。 :-O 这真的解决了!请发布它作为答案。 :-)
  • 已经在里面了 :)
  • 感谢您的帮助。

标签: jsf jsf-2 primefaces datatable commandbutton


【解决方案1】:

actionListener 应该创建为 MethodExpression 而不是 ValueExpression:

  1. 我假设factory instanceOf ExpressionFactory。使用createMethodExpression factory

    MethodExpression targetExpression = factory.createMethodExpression( elContext, "#{complianceCaseManager.selectedComplianceCaseWithRefresh(coca)}",null,new Class[]{ComplianceCase.class} );
    
  2. 向组件添加监听器:

    button.addActionListener( new MethodExpressionActionListener(targetExpression));
    
  3. 与当前问题不完全相关,您还省略了组件的id 属性。为了安全起见,添加

    button.setId("theButton");
    

    编辑:动态创建命令组件时,您绝对必须设置id 属性

【讨论】:

  • 它无法工作。根据community.jboss.org/message/616594#616594 和Java 文档,SetPropertyActionListenerImpl 构造函数的签名是com.sun.faces.taglib.jsf_core.SetPropertyActionListenerImpl.SetPropertyActionListenerImpl(ValueExpression target, ValueExpression value)。 MethodExpression 不继承自 ValueExpression,仅继承自 Expression。
  • 这可能是使用直接 EL 2.2 方法调用的最后手段。但是,我想知道如何将“老派”JSF 1.2 &lt;f:setPropertyActionListener&gt;s 转换为编程变体。查看我的更新以查看纯 JSF 中的 &lt;p:commandButton&gt;。
【解决方案2】:

我曾经使用 lambda 表达式来解决它:

private final ActionListener actionListener = (ActionEvent event) -> {
            //code to execute
        };

然后只是:

  1. 设置命令按钮 ID comandButton.setId(id);
  2. 添加de ActionListener commandButon.addActionListener(actionListener);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-06-27
    • 2012-05-06
    • 2011-05-22
    • 1970-01-01
    • 1970-01-01
    • 2015-01-22
    • 2013-07-24
    • 2013-01-14
    相关资源
    最近更新 更多