从自定义布局p更新另一个xhtml表单中的组件:selectOneRadio无法正常工作

时间:2015-08-30 18:59:13

标签: jsf-2 primefaces

我的xhtml分为菜单区域(defaultMenu.xhtml)和内容区域(defaultContent.xhtml)。

defaultMenu.xhtml的代码是:

<h:form id="defaultmenuform">
    <p:outputPanel id="menupanel" class="contain auto-fixed-center">
        <p:panel id="pmenu" visible="#{phController.user.menuVisible}">
            <table id="stutable">
            <tr>
            <td width="15%">
                <p:outputLabel id="stuname" value="#{phController.phBean.studentName}" />
            </td>
            <td>
                <p:tabMenu activeIndex="#{param.selectedtab}">
                    <p:menuitem value="Home" outcome="phome" icon="ui-icon-star">
                        <f:param name="selectedtab" value="0" />
                    </p:menuitem>
                    <p:menuitem value="Bank" outcome="bhome" icon="ui-icon-person">
                        <f:param name="selectedtab" value="1" />
                    </p:menuitem>
                </p:tabMenu>
            </td>
            </tr>
            </table>
        </p:panel>
    </p:outputPanel>
</h:form>

defaultContent.xhtml实际显示ph.xhtml内容(作为功能导航的一部分),代码为:

<ui:define name="content">

<f:event listener="#{phController.readPeople}" type="preRenderView">
</f:event>

<h:form id="form">

<p:selectOneRadio id="selstud" value="#{phController.phBean.ssSeq}" layout="custom">
    <p:ajax update=":defaultmenuform:parentmenupanel :defaultmenuform:stuname" listener="#{phController.onChangePerson}"/>
    <f:selectItems value="#{phController.selectStudents}" />
</p:selectOneRadio>

    <div style="width: 300px; float:left;">
        <p:dataGrid var="studentlist" value="#{phController.listStudent}" columns="1" rowIndexVar="stuindex">
            <p:panel header="" style="text-align:left">
                <h:panelGrid columns="1" style="width:100%">
                    <h:outputText value="#{studentlist.studentName}" />

                    <p:radioButton for=":form:selstud" itemIndex="#{stuindex}"/> Select

                 </h:panelGrid>
            </p:panel>
        </p:dataGrid>
    </div>

    </h:form>
</ui:define>

支持bean的代码是:

    Map<String, Object> studentparam = new HashMap<>();
    studentparam.put("studentSeq", phBean.getSsSeq());

    lS = getBaseDAOService().readStudent("readStudent", studentparam);
    phBean.setStudentName(lS.get(0).getStudentFirstName() + " " + lS.get(0).getStudentLastName());

如您所见,我调用onChangeStu方法在defaultMenu.xhtml中显示所选的Student Name。我正在使用自定义布局p:phxhtml中的selectOneRadio和onClick尝试更新defaultMenu.xhtml中的p:outputLabel。

成功调用了backing bean方法,并且该值也在变量phController.phBean.studentName中设置,但更新不起作用。我还使用查看源检查并且id是“:defaultmenuform:stuname”,我也尝试更新菜单面板“:defaultmenuform:menupanel”,但这些都不起作用。

不确定如何解决此问题。请建议。

包括所有.xhtmls的结构

<h:body id="entirePageBody">
    <div id="page">

        <ui:insert name="header" >
            <ui:include src="/template/defaultHeader.xhtml" />
        </ui:insert>

        <ui:insert name="menu" >
            <ui:include src="/template/defaultMenu.xhtml" />
        </ui:insert>


        <div id="content_div" class="auto-fixed-center">
            <div id="content_div_padding" class="content-block"> 
                <ui:insert name="content" >
                    <ui:include src="/template/defaultContent.xhtml" />
                    <ui:debug hotkey="z" />
                </ui:insert>
        </div>
        </div>

        <ui:insert name="footer" >
            <ui:include src="/template/defaultFooter.xhtml" />
        </ui:insert>

   </div>
</h:body>

PhController.java:

公共类PhController扩展BaseController实现Serializable {

private List<Stud> listStudent;
private List selectStudents;
SelectItem option;
private PhBean phBean;
private Boolean menuVisible;

int counter = 0;

public PhController() {

    phBean = new PhBean();
}

public void readPeople() {

    listStudent = new ArrayList<Stud>();
    listStudent.add(new Stud(1, "John Miller"));
    listStudent.add(new Stud(2, "Scott Jackson"));

    selectStudents = new ArrayList();

    option = new SelectItem(listStudent.get(0).getStudentSeq(), "Select");
    selectStudents.add(option);

    option = new SelectItem(listStudent.get(1).getStudentSeq(), "Select");
    selectStudents.add(option);

    phBean.setSsSeq(String.valueOf(1));
    phBean.setSelectedName(listStudent.get(0).getStudentName());

    menuVisible = true;

}

public void onChangePerson() {

    phBean.setSelectedName(listStudent.get(1).getStudentName());
}

// Getters and Setters

}

PhBean.java:

公共类PhBean实现Serializable {

private String ssSeq;
private String studName;    // Used to display the name in the Menu bar.
private String selectedName;

public PhBean() {
}

// Getters and Setters

}

1 个答案:

答案 0 :(得分:0)

我要说在p:ajax defaultContent.xhtml中要更新的组件列表应该只用空格分隔,不能用逗号分隔 - 所以请尝试更改它:

update=":defaultmenuform:menupanel, :defaultmenuform:stuname"

到此:

update=":defaultmenuform:menupanel :defaultmenuform:stuname"

<强>更新

我更多地玩了这个并且可能找到了线索 - 请将以下代码添加到defaultmenuform

<p:messages autoUpdate="true" showDetail="true" />

这应该有助于我们跟踪验证失败的原因(如果验证失败是您的根本原因 - 正如我所说,我复制此问题的可能性相当有限。)

无论如何,当我在p:selectOneRadio中选择了一些项目时,会出现如下错误消息:

Conversion Error setting value 'test001.Student@4110c95c' for 'null Converter'.

根本原因在于这一行:

<p:selectOneRadio id="selstud" value="#{phController.phBean.ssSeq}" layout="custom">

p:selectOneRadio只希望将String作为value传递 - 而ssSeq很可能是另一种类型。尝试更改填充value的方式,以确保它始终为String - 可能是phBean的不同属性,或者只是一个全新的String属性。

注意:如果这没有帮助,也许您可​​以使用非常简单的示例来更新您的问题:phControllerphBean如果我们要测试它们会是什么样子。

更新#2

因此,您已经解释了每次加载/刷新页面时都要调用phController.readPeople的问题,而是每次Ajax请求都会加载它,从而覆盖这些值。

在你的PhController(它是一个bean,对吧?会话作用域?)你可以添加这样的东西(为了便于阅读,省略了null检查):

public void readPeopleOnGet() {
    FacesContext fc = FacesContext.getCurrentInstance();
    ExternalContext ec = fc.getExternalContext();
    HttpServletRequest req = (HttpServletRequest) ec.getRequest();
    String reqMethod = req.getMethod();

    if ("GET".equals(reqMethod)) {
        readPeople();
    }
}

使用上面的方法,你可以保留defaultContext.xhtml的这一部分,只要它实际被调用(我假设是这样),只是改变了监听器方法:

<f:event listener="#{phController.readPeopleOnGet}" type="preRenderView">
</f:event>

对于页面的每个请求,仍会调用方法readPeopleOnGet,但由于Ajax请求为POST,因此只有在页面加载或刷新时才会调用readPeople

这可能不是一个“完全干净”的解决方案,但在我测试它时似乎正常工作。

更新#3

好吧,既然你使用了PrimeFaces,就可以通过这种方式识别Ajax:

public void readPeopleOnGet() {
    RequestContext rc = RequestContext.getCurrentInstance();

    if (!rc.isAjaxRequest()) {
        readPeople();
    }
}

但是如果我从最新的评论中得到你的观点,那么你只想在第一次加载页面时运行readPeople - 所以下面的部分可能会更好。

如果PhController实际上是一个bean,你没有回答,但我认为它是(你发布的代码中没有可见的注释)。您可以尝试制作@SessionScoped

@ManagedBean
@SessionScoped
public class PhController extends BaseController implements Serializable {
// the rest of the PhController goes here...

然后你可以在PhController

中添加这样的内容
@PostConstruct
private void init() {
    readPeople();
}

注释@PostConstruct确保在创建bean之后只调用一次方法init。您可以根据需要继续从其他位置调用方法readPeople,同时删除<f:event ... />readPeopleOnGet,因为这些将不再需要。