Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/jsf-2/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Jsf 2 PrimeFaces SelectCheckBox菜单:切换选择actionListener中的旧值_Jsf 2_Primefaces - Fatal编程技术网

Jsf 2 PrimeFaces SelectCheckBox菜单:切换选择actionListener中的旧值

Jsf 2 PrimeFaces SelectCheckBox菜单:切换选择actionListener中的旧值,jsf-2,primefaces,Jsf 2,Primefaces,在我的JSF视图中,我有一个p:selectCheckboxMenu,我想通过AJAX对所选值执行一些业务逻辑 对于一个简单的change事件,它可以正常工作,但对于切换选择事件则不行。在我的listener方法中,我正在检索旧的选择,但我在这里期待新的选择 请参见以下示例: @ViewScoped @Named public class RequestBean implements Serializable { private List<String> list; // +

在我的JSF视图中,我有一个
p:selectCheckboxMenu
,我想通过AJAX对所选值执行一些业务逻辑

对于一个简单的
change
事件,它可以正常工作,但对于
切换选择
事件则不行。在我的listener方法中,我正在检索旧的选择,但我在这里期待新的选择

请参见以下示例:

@ViewScoped
@Named
public class RequestBean implements Serializable {
    private List<String> list; // + getter/setter

    @PostConstruct
    private void init() {       
        list = new ArrayList<String>() {{
          add("one");  add("two"); add("three");
        }};
    }

    public void listener() {
        System.out.println("Current content of \"list\":");
        for(String s : list) {
            System.out.println(s);
        }
    }
}
但预期结果如下所示:

Info:   Current content of "list":
Info:   one
Info:   two
Info:   three
对于常规更改事件,它按预期工作。在这里,我得到了监听器中的新选择。我该怎么修?或者我做错了什么


GlassFish 4.1,在Java 1.8.045上运行

JSF2.2.10(莫哈拉)

PrimeFaces 5.1

OmniFaces 1.8.1


这个问题似乎与过早调用侦听器有关。在进行一些基本调试时,我发现
toggleSelect
在更新模型值之前调用侦听器方法,而
change
事件在修改模型值之后调用侦听器方法。这是我当前的代码:

RequestBean:

@ViewScoped
@ManagedBean
public class RequestBean implements Serializable {
    public List<String> getList() {
        return list;
    }

    public void setList(List<String> list) {
        this.list = list;
        System.out.println("Values set: " + list);
    }

    private List<String> list;

    @PostConstruct
    private void init() {
        list = new ArrayList<String>() {
            {
                add("one");
                add("two");
                add("three");
            }
        };
    }

    public void listener() {
        System.out.println("Listener called!");
    }
}
<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:h="http://xmlns.jcp.org/jsf/html"
    xmlns:f="http://xmlns.jcp.org/jsf/core"
    xmlns:p="http://primefaces.org/ui"
    xmlns:comp="http://java.sun.com/jsf/composite/comp"
    xmlns:ui="http://java.sun.com/jsf/facelets">
<h:head />
<h:body>
    <h:form>
        <p:selectCheckboxMenu value="#{requestBean.list}" label="List">
            <f:selectItem itemValue="one" itemLabel="one" />
            <f:selectItem itemValue="two" itemLabel="two" />
            <f:selectItem itemValue="three" itemLabel="three" />
            <p:ajax event="toggleSelect" listener="#{requestBean.listener}" />
            <p:ajax event="change" listener="#{requestBean.listener}" />
        </p:selectCheckboxMenu>
    </h:form>
</h:body>
</html>
最后一个是toogle选择,正如您所看到的,模型已正确更新,但侦听器之前已被调用

让我们用一个定制的
PhaseListener
多玩一会儿:

Entering RESTORE_VIEW 1
Entering APPLY_REQUEST_VALUES 2
Entering PROCESS_VALIDATIONS 3
Entering UPDATE_MODEL_VALUES 4
Values set: [one]
Entering INVOKE_APPLICATION 5
Listener called!
Entering RENDER_RESPONSE 6
Entering RESTORE_VIEW 1
Entering APPLY_REQUEST_VALUES 2
Entering PROCESS_VALIDATIONS 3
Entering UPDATE_MODEL_VALUES 4
Values set: [one, two]
Entering INVOKE_APPLICATION 5
Listener called!
Entering RENDER_RESPONSE 6
Entering RESTORE_VIEW 1
Entering APPLY_REQUEST_VALUES 2
Listener called!
Entering PROCESS_VALIDATIONS 3
Entering UPDATE_MODEL_VALUES 4
Values set: [one, two, three]
Entering INVOKE_APPLICATION 5
Entering RENDER_RESPONSE 6
如您所见,模型值总是在
UPDATE\u model\u values
阶段设置,而
change
事件在
INVOKE\u APPLICATION
中执行,它应该在列表的前面执行

这似乎是一个Primefaces错误,应该在中通知它

另请参见:

@ViewScoped
@ManagedBean
public class RequestBean implements Serializable {
    public List<String> getList() {
        return list;
    }

    public void setList(List<String> list) {
        this.list = list;
        System.out.println("Values set: " + list);
    }

    private List<String> list;

    @PostConstruct
    private void init() {
        list = new ArrayList<String>() {
            {
                add("one");
                add("two");
                add("three");
            }
        };
    }

    public void listener() {
        System.out.println("Listener called!");
    }
}
<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:h="http://xmlns.jcp.org/jsf/html"
    xmlns:f="http://xmlns.jcp.org/jsf/core"
    xmlns:p="http://primefaces.org/ui"
    xmlns:comp="http://java.sun.com/jsf/composite/comp"
    xmlns:ui="http://java.sun.com/jsf/facelets">
<h:head />
<h:body>
    <h:form>
        <p:selectCheckboxMenu value="#{requestBean.list}" label="List">
            <f:selectItem itemValue="one" itemLabel="one" />
            <f:selectItem itemValue="two" itemLabel="two" />
            <f:selectItem itemValue="three" itemLabel="three" />
            <p:ajax event="toggleSelect" listener="#{requestBean.listener}" />
            <p:ajax event="change" listener="#{requestBean.listener}" />
        </p:selectCheckboxMenu>
    </h:form>
</h:body>
</html>

侦听器在JSF生命周期的第二阶段被触发:应用请求值。模型(
requestBean.list
)稍后在第四阶段更新模型值。这就是为什么侦听器看到旧的值

BalusC发布了一个通用的解决方案,但在这种情况下,由于PrimeFaces的组件包装和排队事件的方式,它将导致无限循环。所以我建议你走这条路

查看

<f:view beforePhase="#{requestBean.beforePhase}">
    <h:form id="form">
        <p:selectCheckboxMenu id="list_menu" value="#{requestBean.list}" label="List">
            <f:selectItem itemValue="one" itemLabel="one" />
            <f:selectItem itemValue="two" itemLabel="two" />
            <f:selectItem itemValue="three" itemLabel="three" />
            <!-- still need p:ajax toggleSelect to trigger the request -->
            <p:ajax event="toggleSelect" />
            <p:ajax event="change" listener="#{requestBean.listener}" />
        </p:selectCheckboxMenu>
    </h:form>
</f:view>
<p:selectCheckboxMenu 
    value="#{bean.selectedValues}" 
    label="#{bean.selectedValuesDisplayString}"
    widgetVar="checkboxMenuWget">

    <f:selectItems value="#{bean.allValues}"/> 

    <p:ajax event="change" listener="#{bean.updateDisplayString()}" update="@widgetVar(checkboxMenuWget)" />
    <p:ajax event="toggleSelect" update="@widgetVar(checkboxMenuWget)" />
</p:selectCheckboxMenu>

Bean

public void beforePhase(PhaseEvent event) {
    if (event.getPhaseId() == PhaseId.INVOKE_APPLICATION) {
        Map<String, String> params = FacesContext.getCurrentInstance()
                .getExternalContext().getRequestParameterMap();
        String eventName = params.get(
                Constants.RequestParams.PARTIAL_BEHAVIOR_EVENT_PARAM);
        String source = params.get("javax.faces.source");
        if ("form-list_menu".equals(source) && "toggleSelect".equals(eventName)) {
            listener();
        }
    }
}
// Properties
private List<String> allValues;
private List<String> selectedValues;
private String selectedValuesDisplayString;

// Getters and Setters
public void setSelectedValues(List<String> selectedValues) {
    this.selectedValues = selectedValues;
    updateDisplayString();
}

// UI Code
public void updateDisplayString() {
    this.selectedValuesDisplayString = // code to generate display string...
}
前期公共作废(阶段事件){
if(event.getPhaseId()==PhaseId.INVOKE_应用程序){
Map params=FacesContext.getCurrentInstance()
.getExternalContext().getRequestParameterMap();
字符串eventName=params.get(
常量.RequestParams.PARTIAL_BEHAVIOR_EVENT_PARAM);
字符串source=params.get(“javax.faces.source”);
if(“表单列表\菜单”.equals(源)&&&“切换选择”.equals(事件名称)){
监听器();
}
}
}

我偶然发现了另一种解决方法:基本上,您需要从setter中填充标签文本以获得值。例如:

查看

<f:view beforePhase="#{requestBean.beforePhase}">
    <h:form id="form">
        <p:selectCheckboxMenu id="list_menu" value="#{requestBean.list}" label="List">
            <f:selectItem itemValue="one" itemLabel="one" />
            <f:selectItem itemValue="two" itemLabel="two" />
            <f:selectItem itemValue="three" itemLabel="three" />
            <!-- still need p:ajax toggleSelect to trigger the request -->
            <p:ajax event="toggleSelect" />
            <p:ajax event="change" listener="#{requestBean.listener}" />
        </p:selectCheckboxMenu>
    </h:form>
</f:view>
<p:selectCheckboxMenu 
    value="#{bean.selectedValues}" 
    label="#{bean.selectedValuesDisplayString}"
    widgetVar="checkboxMenuWget">

    <f:selectItems value="#{bean.allValues}"/> 

    <p:ajax event="change" listener="#{bean.updateDisplayString()}" update="@widgetVar(checkboxMenuWget)" />
    <p:ajax event="toggleSelect" update="@widgetVar(checkboxMenuWget)" />
</p:selectCheckboxMenu>

Bean

public void beforePhase(PhaseEvent event) {
    if (event.getPhaseId() == PhaseId.INVOKE_APPLICATION) {
        Map<String, String> params = FacesContext.getCurrentInstance()
                .getExternalContext().getRequestParameterMap();
        String eventName = params.get(
                Constants.RequestParams.PARTIAL_BEHAVIOR_EVENT_PARAM);
        String source = params.get("javax.faces.source");
        if ("form-list_menu".equals(source) && "toggleSelect".equals(eventName)) {
            listener();
        }
    }
}
// Properties
private List<String> allValues;
private List<String> selectedValues;
private String selectedValuesDisplayString;

// Getters and Setters
public void setSelectedValues(List<String> selectedValues) {
    this.selectedValues = selectedValues;
    updateDisplayString();
}

// UI Code
public void updateDisplayString() {
    this.selectedValuesDisplayString = // code to generate display string...
}
//属性
私有列表所有值;
私有列表选择值;
私有字符串selectedValuesDisplayString;
//接球手和接球手
公共无效设置selectedValues(列出selectedValues){
this.selectedValues=selectedValues;
updateDisplayString();
}
//用户界面代码
public void updateDisplayString(){
this.selectedValuesDisplayString=//生成显示字符串的代码。。。
}

我也面临这个问题。它在PrimeFaces 5.2中仍然没有固定。我的解决方案是如何修复它:

添加到faces-config.xml

<component>
    <component-type>org.primefaces.component.SelectCheckboxMenu</component-type>
    <component-class>yourpackage.SelectCheckboxMenu</component-class>
</component>

org.primefaces.component.selectCheckBox菜单
您的软件包。选择复选框菜单
创建此类:

public class SelectCheckboxMenu extends  org.primefaces.component.selectcheckboxmenu.SelectCheckboxMenu {
    @Override
    public void queueEvent(FacesEvent event) {
        FacesContext context = getFacesContext();
        String eventName = context.getExternalContext().getRequestParameterMap().get(Constants.RequestParams.PARTIAL_BEHAVIOR_EVENT_PARAM);

        if(event instanceof AjaxBehaviorEvent && eventName.equals("toggleSelect")) {
            Map<String,String> params = context.getExternalContext().getRequestParameterMap();
            String clientId = this.getClientId(context);
            boolean checked = Boolean.valueOf(params.get(clientId + "_checked"));

            // changed code
            ToggleSelectEvent toggleSelectEvent = new ToggleSelectEvent(this, ((AjaxBehaviorEvent) event).getBehavior(), checked);
            toggleSelectEvent.setPhaseId(event.getPhaseId());
            getParent().queueEvent(toggleSelectEvent);
            // end
        }
        else {
            super.queueEvent(event);
        }
    }

}
公共类SelectCheckboxMenu扩展org.primefaces.component.SelectCheckboxMenu.SelectCheckboxMenu{
@凌驾
public void queueEvent(FacesEvent事件){
FacesContext context=getFacesContext();
String eventName=context.getExternalContext().getRequestParameterMap().get(Constants.RequestParams.PARTIAL_BEHAVIOR_EVENT_PARAM);
if(AjaxBehaviorEvent的事件实例&&eventName.equals(“切换选择”)){
Map params=context.getExternalContext().getRequestParameterMap();
字符串clientId=this.getClientId(上下文);
boolean checked=boolean.valueOf(params.get(clientId+“_checked”);
//更改代码
ToggleSelectEvent ToggleSelectEvent=新建ToggleSelectEvent(此,((AjaxBehaviorEvent)事件).getBehavior(),选中);
切换SelectEvent.setPhaseId(event.getPhaseId());
getParent().queueEvent(切换SelectEvent);
//结束
}
否则{
super.queueEvent(事件);
}
}
}

您可以对侦听器使用远程命令,如下所示

<p:remoteCommand name="test" id="test" actionListener"#{requestBean.listener}" update="@form" process="@form"></p:remoteCommand>

在toggleselect上调用上述代码的以下方法

        <p:ajax event="toggleSelect" oncomplete="test();" />

面临同样的问题,在搜索了一段时间后,我发现您可以将更新逻辑绑定到
onchange
属性。比如:

<p:selectCheckboxMenu value="#{requestBean.list}" label="List" onchange="#{requestBean.listener()}">
            <f:selectItem itemValue="one" itemLabel="one" />
            <f:selectItem itemValue="two" itemLabel="two" />
            <f:selectItem itemValue="three" itemLabel="three" />
            <p:ajax event="toggleSelect" listener="#{requestBean.listener}" />
            <p:ajax event="change" listener="#{requestBean.listener}" />
        </p:selectCheckboxMenu>

考虑:
onchange=“#{requestBean.listener()}”
您必须使用大括号调用侦听器,否则会出现异常


不知道您使用的是哪个PF版本,但我在中找到了解决方案。(PrimeFaces 5.3)

谢谢,我现在看到并理解了这种行为。但是,如果能够在bean中提供选择选项的完整列表,则可以使用ToggleSelectEvent:
public void toggle(ToggleSelectEvent te){if(te.isSelected()){//do sth with this.items}}
。。。也许这对s.o.还有帮助:)使用它没有问题,只要您在最后执行整个表单提交,因为模型会正确刷新。问题可能是