嵌套ui:repeat元素中的h:selectOneRadio组问题 [英] h:selectOneRadio group problem within nested ui:repeat elements

查看:61
本文介绍了嵌套ui:repeat元素中的h:selectOneRadio组问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在尝试实现一个动态调查页面,其中包含用户(大型应用程序的一部分)定义的页面,部分和问题.用户可以定义不同的问题类型,这将呈现不同的组件(无线电,文本区域,文本字段,选择列表等).该应用当前已部署在Wildfly 16/Java 8/JSF 2.3/Servlet 4中.

I'm currently trying to implement a dynamic survey page containing pages, sections and questions defined by the user (part of a larger application). The user may defined different question types, which will render a different component (radio, textarea, textfield, selectionlist, ...). This app is currently deployed in Wildfly 16 / Java 8 / JSF 2.3 / Servlet 4.

由于用户可以为单选按钮定义一组特定的值和关联的图像,因此我需要自定义单选按钮的输出.因此,我的选择是使用 selectoneradio 中可用的新 group 属性.在多级 ui:repeat 中使用此新属性会导致行为不稳定.

Since the user may define a specific set of values and associated images for the radio button, I need to customize the radio button output. So my option was to use the new group attribute available in selectoneradio. Using this new attribute is causing erratic behaviour when used inside a multi-level ui:repeat.

为了说明问题,简化并创建了以下示例.

The following example was simplified and created in order to illustrate the problem.

课程

package test;

import java.io.Serializable;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import javax.annotation.PostConstruct;
import javax.faces.view.ViewScoped;
import javax.inject.Named;

@Named("test")
@ViewScoped
public class Test implements Serializable
{
    private static final long serialVersionUID = 1L;

    private static Map<String, Map<String, String>> questionMap = new TreeMap<>();

    private static Map<String, String> fixedValuesMap = new TreeMap<>();

    private Map<String, String> answerMap = new TreeMap<>();

    private List<String> sections = Arrays.asList("Section_1", "Section_2", "Section_3", "Section_4");

    static
    {
        fixedValuesMap.put("1", "Value 1");
        fixedValuesMap.put("2", "Value 2");
        fixedValuesMap.put("3", "Value 3");
        fixedValuesMap.put("4", "Value 4");
        fixedValuesMap.put("5", "Value 5");

        Map<String, String> sec1questions = new TreeMap<>();
        sec1questions.put("1", "Question 1");
        sec1questions.put("2", "Question 2");
        sec1questions.put("3", "Question 3");
        questionMap.put("Section_1", sec1questions);

        Map<String, String> sec2questions = new TreeMap<>();
        sec2questions.put("4", "Question 4");
        questionMap.put("Section_2", sec2questions);

        Map<String, String> sec3questions = new TreeMap<>();
        sec3questions.put("5", "Question 5");
        questionMap.put("Section_3", sec3questions);

        Map<String, String> sec4questions = new TreeMap<>();
        sec4questions.put("6", "Question 6");
        questionMap.put("Section_4", sec4questions);
    }

    public Test()
    {
    }

    @PostConstruct
    private void init()
    {
        answerMap.put("1", null);
        answerMap.put("2", null);
        answerMap.put("3", null);
        answerMap.put("4", null);
        answerMap.put("5", null);
        answerMap.put("6", null);
    }

    public String getQuestionType(String index)
    {
        switch(index)
        {
            case "1":
                return "RADIO_BUTTON";
            case "2":
                return "RADIO_BUTTON";
            case "3":
                return "RADIO_BUTTON";
            case "4":
                return "TEXT_AREA";
            case "5":
                return "RADIO_BUTTON";
            case "6":
                return "FREE_TEXT";
            default:
                return "FREE_TEXT";
        }
    }

    public Map<String, String> getQuestions(String section)
    {
        return questionMap.get(section);
    }

    public Map<String, String> getAnswerMap()
    {
        return answerMap;
    }

    public Map<String, String> getFixedValues()
    {
        return fixedValuesMap;
    }

    public List<String> getSections()
    {
        return sections;
    }

    public void changeRadio(String questionKey, String questionValue)
    {
        answerMap.put(questionKey, questionValue);
    }

    public String submit()
    {
        for(Map.Entry<String, String> entry : answerMap.entrySet())
            System.out.println("ENTRY: " + entry.getKey() + " - " + entry.getValue());

        return null;
    }
}

XHTML

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
        xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
        xmlns:f="http://xmlns.jcp.org/jsf/core"
        xmlns:h="http://xmlns.jcp.org/jsf/html"
        xmlns:a="http://xmlns.jcp.org/jsf/passthrough">

    <h:head>
        <meta charset="utf-8"/>
        <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"/>
        <meta name="description" content="My Test"/>

        <link rel="stylesheet" href="#{request.contextPath}/resources/bootstrap/css/bootstrap.min.css" />
        <title>My Test</title>
    </h:head>

    <h:body>

        <div class="container-fluid">

            <div class="row">

                <main role="main" class="col-md-9 ml-sm-auto col-lg-10 px-4">

                    <div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
                        <h1 class="h2">UI Repeat Test</h1>
                    </div>

                    <h:form role="form" prependId="false">

                        <div class="row mx-2">

                            <ui:repeat var="sec" value="#{test.sections}">

                                <div class="col-12">

                                    <ui:repeat var="question" value="#{test.getQuestions(sec)}">

                                        <div>
                                            <div class="col-12">
                                                <div class="form-group">
                                                    <label for="answer">#{question.key} - #{question.value}</label>

                                                    <div class="col-12">

                                                        <h:panelGroup rendered="#{test.getQuestionType(question.key) eq 'FREE_TEXT'}" layout="block">
                                                            <h:inputText value="#{test.answerMap[question.key]}" styleClass="form-control"/>
                                                        </h:panelGroup>

                                                        <h:panelGroup rendered="#{test.getQuestionType(question.key) eq 'TEXT_AREA'}"  layout="block">
                                                            <h:inputTextarea value="#{test.answerMap[question.key]}" styleClass="form-control" rows="2" />
                                                        </h:panelGroup>

                                                        <h:panelGroup rendered="#{test.getQuestionType(question.key) eq 'RADIO_BUTTON'}"  layout="block">

                                                            <table class="radio-label checkbox">
                                                                <tbody>
                                                                    <tr>
                                                                        <ui:repeat var="item" value="#{test.fixedValues.entrySet()}">
                                                                            <td class="text-center grid-margin">    
                                                                                <h:selectOneRadio group="#{question.key}" value="#{test.answerMap[question.key]}" layout="lineDirection" styleClass="checkbox"  >
                                                                                        <f:selectItem itemValue="#{item.key}" itemLabel="#{item.value}" />
                                                                                </h:selectOneRadio>
                                                                            </td>   
                                                                        </ui:repeat>
                                                                    </tr>
                                                                </tbody>
                                                            </table>

                                                        </h:panelGroup>

                                                    </div>  
                                            </div>
                                            </div>
                                        </div>

                                    </ui:repeat>

                                </div>

                            </ui:repeat>

                        </div>

                        <div class="row mx-2 my-2">
                            <div class="col-12">
                                <h:commandButton value="Test Me" type="submit" action="#{test.submit}" styleClass="btn btn-primary" />
                            </div>
                        </div>

                    </h:form>

                </main>

            </div>

        </div>

        <script src="#{request.contextPath}/resources/jquery/jquery.slim.min.js"></script>
        <script src="#{request.contextPath}/resources/bootstrap/js/bootstrap.bundle.min.js"></script>

    </h:body>

</html>

提交表单时,仅存储最后一个单选按钮和文本字段值.如果我替换了selectItems ui:repeat

When the form is submitted only the last radio button and text field values are stored. If I replace the selectItems ui:repeat

<table class="radio-label checkbox">
  <tbody>
    <tr>
      <ui:repeat var="item" value="#{test.fixedValues.entrySet()}">
        <td class="text-center grid-margin">    
          <h:selectOneRadio group="#{question.key}" value="#{test.answerMap[question.key]}" layout="lineDirection" styleClass="checkbox"  >
            <f:selectItem itemValue="#{item.key}" itemLabel="#{item.value}" />
          </h:selectOneRadio>
        </td>   
      </ui:repeat>
    </tr>
  </tbody>
</table>

使用

<h:selectOneRadio value="#{test.answerMap[question.key]}" layout="lineDirection" >
  <f:selectItems value="#{test.fixedValues.entrySet()}" var="item" itemLabel="#{item.key}" itemValue="#{item.value}" />
</h:selectOneRadio>

一切正常.

我确实需要使用第一个选项,因此可以将一些图像添加到单选按钮值中.
我想念什么吗?

I really need to use the first option, so I can add some images to the radio button values.
Am I missing something?

推荐答案

似乎您已发现问题.我尝试将示例简化如下:

It seemes like you have found an issue. I tried to simplify the example as follows:

我的托管Bean:

package my.pkg;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.PostConstruct;
import javax.enterprise.context.RequestScoped;
import javax.inject.Named;

@Named
@RequestScoped
public class MyBean {
    private List<String> items;

    private List<Number> numbers;

    private Map<String, Object> mapVal;

    @PostConstruct
    public void init() {
        mapVal = new LinkedHashMap<>();
        items = new ArrayList<>();
        numbers = new ArrayList<>();
        for (int i = 0; i < 3; i++) {
            items.add("group_" + i);
            numbers.add(i);
        }
    }

// getters/setters ...

}

示例表格:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
    xmlns:f="http://xmlns.jcp.org/jsf/core"
    xmlns:h="http://xmlns.jcp.org/jsf/html"
    xmlns:c="http://xmlns.jcp.org/jsp/jstl/core">

<h:head />

<h:body>

    <h:form id="frm1">

        <ui:repeat var="grp" value="#{myBean.items}">

            <ui:repeat var="num" value="#{myBean.numbers}" varStatus="stat">

                <h:selectOneRadio id="radioButton" value="#{myBean.mapVal[grp]}"
                    group="myGroup_#{grp}">
                    <f:selectItem itemValue="#{num}" itemLabel="#{grp}: #{num}" />
                </h:selectOneRadio>

                <br />

            </ui:repeat>

            <hr />
        </ui:repeat>

        <h:commandButton value="submit" />

        <h:outputText value="myBean.mapVal: #{myBean.mapVal}" />
    </h:form>

</h:body>
</html>

用户界面输入示例:

提交后,我希望输出为:

After submission I'd expect output to be:

myBean.mapVal: {group_0=0, group_1=1, group_2=2}

但这是

myBean.mapVal: {group_2=2}

第0组和第1组中的单选按钮失去选择.

The radio buttons from group 0 and 1 lose their selection.

对于某些输入,我得到了预期的结果:

For some inputs I get the expected results:

myBean.mapVal: {group_0=0, group_1=0, group_2=0}
myBean.mapVal: {group_0=1, group_1=1, group_2=1}
myBean.mapVal: {group_0=2, group_1=2, group_2=2}

...使用Mojarra 2.3.9.

... using Mojarra 2.3.9.

对于MyFaces 2.3.4,我在上面的屏幕截图中获得了预期的选择结果

For MyFaces 2.3.4 I get the expected result for the selection in above screenshot:

{group_0=0, group_1=1, group_2=2}

但其他选择失败:

1)
expected: {group_0=0, group_1=0, group_2=0}
but is: {group_2=0}

2)
expected: {group_0=0, group_1=0, group_2=2}
but is: {group_1=0, group_2=2}

3)
expected: {group_0=1, group_1=1, group_2=0}
but is: {group_1=1, group_2=0}

我认为我们应该报告Mojarra的问题,以及(如果尚未存在)MyFaces的问题.

In my opinion we should reportan issue for Mojarra and ( if not already present) for MyFaces.

解决方法

如果我替换

    <ui:repeat var="grp" value="#{myBean.items}">

作者

    <c:forEach var="grp" items="#{myBean.items}">

我获得了Mojarra和MyFaces的预期结果.

I get the expected results for Mojarra and MyFaces.

这篇关于嵌套ui:repeat元素中的h:selectOneRadio组问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆