【问题标题】:Can't get MenuItem to have its ActionListeners called无法让 MenuItem 调用其 ActionListener
【发布时间】:2012-02-10 02:37:29
【问题描述】:

我试图让 Primefaces MenuItem [在 Menubar 内] 发出 ActionEvent 并在按下时调用一个方法,但是,监听方法永远不会被调用,我不知道为什么:

xhtml 页面:

<h:body>
<h:form>
    <p:menubar model="#{testBean.model}" />
    <h:commandButton value="submit" />
    <h:outputText value="#{testBean.confirmation}" />
</h:form>
</h:body>
</html>

jsf 豆:

@ManagedBean
public class TestBean implements ActionListener{

    MenuModel model = new DefaultMenuModel();
    private String confirmation = "negative";

    public TestBean() {
        MenuItem item = new MenuItem();
        item.setValue("Click");
        item.setUrl("#");
        item.addActionListener(this);
        model.addMenuItem(item);
    }

    @Override
    public void processAction(ActionEvent event)
            throws AbortProcessingException {

        // EXECUTION NEVER REACHES HERE!
        confirmation = "positive";
    }

    public MenuModel getModel() {
        return model;
    }

    public String getConfirmation() {
        return confirmation;
    }
}

这可能有助于可视化非常简单的输出:

我正在使用 Primefaces 3.1.0 和 JSF 2.0

【问题讨论】:

标签: jsf jsf-2 primefaces actionlistener


【解决方案1】:

我的第一个建议是向您的操作侦听器添加某种调试日志记录,以便了解它是否被调用。如果它被调用但您的网站没有呈现更改,则可能是由于以下原因。

  • 动作监听器不会触发客户端 DOM 的更新。
  • 提交按钮触发请求。托管 bean 被拉起并使用默认值重新初始化,因为它是在请求范围内进行管理的。您应该尝试将您的 bean 放入 @ViewScoped@SessionScoped 管理。

顺便说一句,我们没有实现ActionListener。我们将方法表达式分配给菜单项。这是一个简短的模型示例:我们使用菜单项的操作来切换上下文菜单的按钮状态。希望我能以某种方式帮助你。

Facelet sn-p:

<p:menu model="#{menuBean.model}" />

豆sn-p:

@ManagedBean
@ViewScoped
public class MenuBean implements Serializable {

    private MenuModel model;
    private boolean cutAllowed = false;

    /** Creates a new instance of MenuBean */
    public MenuBean() {
        model = new DefaultMenuModel();

        //First submenu
        Submenu submenu = new Submenu();
        submenu.setLabel("Dynamic Submenu 1");

        MenuItem item = new MenuItem();
        item.setValue("toggle");
        item.setUpdate("contextMenu");
        item.setAjax(true);
        item.setIcon("ui-icon ui-icon-disk");
        ExpressionFactory factory = FacesContext.getCurrentInstance().getApplication().getExpressionFactory();
        MethodExpression methodExpression = factory.createMethodExpression(FacesContext.getCurrentInstance().getELContext(), "#{menuBean.toggleCutState}", String.class, new Class[]{});

        item.setActionExpression(methodExpression);

        submenu.getChildren().add(item);

        model.addSubmenu(submenu);
    }

    public boolean isCutAllowed() {
        return cutAllowed;
    }

    public void setCutAllowed(boolean cutAllowed) {
        this.cutAllowed = cutAllowed;
    }

    public String toggleCutState() {
        toggleCutState(null);
        return null;
    }

    public void toggleCutState(ActionEvent event) {
        this.cutAllowed = !this.cutAllowed;
        System.out.println("toggle called");
    }       

    public MenuModel getModel() {
        return model;
    }  
}

【讨论】:

  • 当你说我们不实现ActionListener,是不是意味着实现ActionListener 行不通?它看起来比你建议的方式简单。
  • 我已经尝试使用@SessionScoped,并进行了调试以确认没有到达代码。 :(
  • @Mowgli 说实话,我什至没有尝试过实现 ActionListener,也不知道它是否可行。我们的菜单栏中有多个操作,因此我们需要为每个菜单项实现一个操作侦听器,这对我来说似乎有点过头了。您是否尝试过使用方法表达式?
  • @Mowgli - 你可以看看这个论坛帖子:forum.primefaces.org/viewtopic.php?f=3&t=7103 - 它讨论了如何使用方法表达式来向菜单项添加动作侦听器。祝你好运.-)
  • 是的,我尝试过使用方法表达式,并且遇到过类似的问题,他们还强迫您将类设为托管 bean。
【解决方案2】:

@Mogwli, item.setId((new UiViewRoot()).createUniqueId());将导致 IllegalArgumentException 因为 new UIViewRoot() 不会感知上下文...应该是 item.setId(FacesContext.getCurrentInstance().getViewRoot().createUniqueId());

【讨论】:

  • 谢谢,您的建议似乎是个好主意。我将更新答案。但是,我没有收到IllegalArgumentExceptions
【解决方案3】:

原始代码的第一个问题是我需要一个唯一的 ID。我很早就发现了这一点,但它导致了另一个非常烦人的问题:会调用动作侦听器,但页面不会更新。要解决此问题(如 here 所述),您可以禁用 MenuItem 上的 ajax 或自定义其更新方式。

正确的构造函数代码是:

public TestBean() {
    MenuItem item = new MenuItem();
    item.setValue("Click");

    // New code:
    item.setId(FacesContext.getCurrentInstance().getViewRoot().createUniqueId());
    item.setAjax(false);

    item.setUrl("#");
    item.addActionListener(this);
    model.addMenuItem(item);
}

【讨论】:

    【解决方案4】:

    首先,您的代码 sn-p 显示一个&lt;h:commandButton&gt;,它不是 Primefaces commandButton &lt;p:commandButton&gt;

    其次,您没有将 commandButton 的 actionListener 属性指定为指向 processAction

    <p:commandButton value="submit" actionListener="#{testBean.processAction}" /> 
    

    【讨论】:

    • 但是监听方法是监听菜单栏项按钮/链接(不是commandButton)。如果 MenuItems 没有发出事件,那么它们就没有 addListener 方法,因此(我认为)在 MenuItem 上只有一个动作侦听器是有效的(我认为)。由于以前的问题,我使用 ,但我会更改它以避免混淆。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-04-01
    • 2013-08-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-02
    • 2013-12-28
    相关资源
    最近更新 更多