다른 콤보박스에서 선택된 항목을 기반으로 맵의 값으로 콤보박스를 동적으로 채웁니다.

StackOverflow https://stackoverflow.com/questions/156852

문제

좋습니다. Java/JavaScript 전문가를 위한 내용은 다음과 같습니다.

내 앱에서 컨트롤러 중 하나가 TreeMap을 JSP에 전달합니다.이 지도에는 자동차 제조업체 이름이 키로, 자동차 개체 목록이 값으로 포함되어 있습니다.이러한 Car 객체는 자동차 이름, ID, 생산 연도 등을 포함하는 간단한 빈입니다.따라서 지도는 다음과 같습니다(이것은 설명을 좀 더 명확하게 하기 위한 예일 뿐입니다).

열쇠:포르쉐
값:세 개의 Car 개체가 포함된 목록(예: 911, Carrera, Boxter, 생산 연도 및 ID 포함)
열쇠:명령
값:두 개의 Car 객체(예: Punto 및 Uno)가 포함된 목록
등...

이제 내 JSP에는 두 개의 콤보 상자가 있습니다.하나는 자동차 제조업체 목록(지도의 키 - 이 부분은 제가 어떻게 해야 하는지 알고 있습니다)을 받아야 하고, 다른 하나는 동적으로 변화하다 사용자가 첫 번째 콤보박스에서 특정 제조업체를 선택하면 자동차 이름을 표시합니다.예를 들어, 사용자가 첫 번째 콤보 상자에서 "Porsche"를 선택하면 두 번째 콤보 상자에는 즉시 "911, Carrera, Boxter"가 표시됩니다...

이 작업을 수행하는 방법을 알아내려고 며칠을 보낸 후, 나는 패배를 인정할 준비가 되었습니다.다양한 시도를 해봤지만 매번 도중 어딘가에 벽에 부딪혔습니다.아무도 내가 이것에 접근하는 방법을 제안할 수 있습니까?네, 저는 JavaScript 초보자입니다. 궁금한 사람이 있다면...

편집하다:나는 이것을 코드 챌린지로 다시 태그했습니다.JavaScript 프레임워크(예: JQuery)를 사용하지 않고 이 문제를 해결한 사람에게 찬사를 보냅니다.

도움이 되었습니까?

해결책 2

어쨌든, 내가 말했듯이, 나는 마침내 혼자서 그것을 할 수 있었으므로 여기에 내 대답이 있습니다 ...

이와 같은 컨트롤러로부터지도를받습니다 (스프링을 사용하고 있습니다. 다른 프레임 워크와 어떻게 작동하는지 모르겠습니다).

<c:set var="manufacturersAndModels" scope="page" value="${MANUFACTURERS_AND_MODELS_MAP}"/>

이것들은 내 콤보입니다.

<select id="manufacturersList" name="manufacturersList" onchange="populateModelsCombo(this.options[this.selectedIndex].index);" >
                  <c:forEach var="manufacturersItem" items="<%= manufacturers%>">
                    <option value='<c:out value="${manufacturersItem}" />'><c:out value="${manufacturersItem}" /></option>
                  </c:forEach>
                </select>


select id="modelsList" name="modelsList"
                  <c:forEach var="model" items="<%= models %>" >
                    <option value='<c:out value="${model}" />'><c:out value="${model}" /></option>
                  </c:forEach>
                </select>

다음 수업을 가져 왔습니다 (일부 이름은 물론 변경되었습니다).

<%@ page import="org.mycompany.Car,java.util.Map,java.util.TreeMap,java.util.List,java.util.ArrayList,java.util.Set,java.util.Iterator;" %>

그리고 모든 노력을하는 코드는 다음과 같습니다.

<script type="text/javascript">
<%  
     Map mansAndModels = new TreeMap();
     mansAndModels = (TreeMap) pageContext.getAttribute("manufacturersAndModels");
     Set manufacturers = mansAndModels.keySet(); //We'll use this one to populate the first combo
     Object[] manufacturersArray = manufacturers.toArray();

     List cars;
     List models = new ArrayList(); //We'll populate the second combo the first time the page is displayed with this list


 //initial second combo population
     cars = (List) mansAndModels.get(manufacturersArray[0]);

     for(Iterator iter = cars.iterator(); iter.hasNext();) {

       Car car = (Car) iter.next();
       models.add(car.getModel());
     }
%>


function populateModelsCombo(key) {
  var modelsArray = new Array();

  //Here goes the tricky part, we populate a two-dimensional javascript array with values from the map
<%                          
     for(int i = 0; i < manufacturersArray.length; i++) {

       cars = (List) mansAndModels.get(manufacturersArray[i]);
       Iterator carsIterator = cars.iterator();           
%>
    singleManufacturerModelsArray = new Array();
<%
    for(int j = 0; carsIterator.hasNext(); j++) {

      Car car = (Car) carsIterator.next();

 %>         
    singleManufacturerModelsArray[<%= j%>] = "<%= car.getModel()%>";
 <%
       }
 %>
  modelsArray[<%= i%>] = singleManufacturerModelsArray;
 <%
     }         
 %>   

  var modelsList = document.getElementById("modelsList");

  //Empty the second combo
  while(modelsList.hasChildNodes()) {
    modelsList.removeChild(modelsList.childNodes[0]);
  }

 //Populate the second combo with new values
  for (i = 0; i < modelsArray[key].length; i++) {

    modelsList.options[i] = new Option(modelsArray[key][i], modelsArray[key][i]);
  }      
}

다른 팁

나는 단지 도전을 좋아합니다.

jQuery, 단지 평범한 JavaScript, 사파리에서 테스트되었습니다.

다음에 대해 다음과 같이 추가하고 싶습니다.

  • 오류 검사로 인해 길다.
  • 두 부분이 생성됩니다. 맵과 제조사 선택의 내용이있는 첫 번째 스크립트 노드
  • 내 컴퓨터에서 작동 (TM) (Safari/OS X)
  • (CSS) 스타일이 적용되지 않습니다. 나는 맛이 좋지 않아서 어쨌든 쓸모가 없다.

.

<body>
  <script>
  // DYNAMIC
  // Generate in JSP
  // You can put the script tag in the body
  var modelsPerManufacturer = {
    'porsche' : [ 'boxter', '911', 'carrera' ],
    'fiat': [ 'punto', 'uno' ]  
  };
  </script>

  <script>
  // STATIC
  function setSelectOptionsForModels(modelArray) {
    var selectBox = document.myForm.models;

    for (i = selectBox.length - 1; i>= 0; i--) {
    // Bottom-up for less flicker
    selectBox.remove(i);  
    }

    for (i = 0; i< modelArray.length; i++) {
     var text = modelArray[i];
      var opt = new Option(text,text, false, false);
      selectBox.add(opt);
    }  
  }

  function setModels() {
    var index = document.myForm.manufacturer.selectedIndex;
    if (index == -1) {
    return;
    }

    var manufacturerOption = document.myForm.manufacturer.options[index];
    if (!manufacturerOption) {
      // Strange, the form does not have an option with given index.
      return;
    }
    manufacturer = manufacturerOption.value;

    var modelsForManufacturer = modelsPerManufacturer[manufacturer];
    if (!modelsForManufacturer) {
      // This modelsForManufacturer is not in the modelsPerManufacturer map
      return; // or alert
    }   
    setSelectOptionsForModels(modelsForManufacturer);
  }

  function modelSelected() {
    var index = document.myForm.models.selectedIndex;
    if (index == -1) {
      return;
    }
    alert("You selected " + document.myForm.models.options[index].value);
  }
  </script>
  <form name="myForm">
    <select onchange="setModels()" id="manufacturer" size="5">
      <!-- Options generated by the JSP -->
      <!-- value is index of the modelsPerManufacturer map -->
      <option value="porsche">Porsche</option>
      <option value="fiat">Fiat</option>
    </select>

    <select onChange="modelSelected()" id="models" size="5">
      <!-- Filled dynamically by setModels -->
    </select>
  </form>

</body>

스트럿을 사용하고 있습니까?

이를 달성하려면 JavaScript 속임수 (또는 Ajax)가 필요합니다.

당신이해야 할 일은 JavaScript 코드 어딘가에 있습니다 (순간에 생성하는 방법을 제외하고) :

var map = {
   'porsche': [ 'boxter', '911', 'carrera' ],
   'fiat': ['punto', 'uno']
};

이것은 기본적으로 서버 측 데이터 구조의 사본, 즉 제조업체가 키워진 맵, 각 값에는 자동차 유형이 있습니다.

그런 다음 제조업체의 OnChange 이벤트에서는 위의 맵에서 배열을 가져온 다음 해당 옵션 목록을 작성해야합니다. (Devguru.com을 확인하십시오 - 표준 JavaScript 객체에 대한 유용한 정보가 많이 있습니다).

그러나 자동차 목록이 얼마나 큰지에 따라 Ajax 경로로가는 것이 가장 좋습니다.

제조업체가 주어진 자동차 유형 목록을 찾은 다음 반환 된 JSP로 전달하는 새 컨트롤러를 만들어야합니다. JSON (JSON 일 필요는 없지만 나에게 잘 작동합니다).

그런 다음 라이브러리를 사용하십시오 jQuery 제조업체 목록의 OnChange 이벤트에서 자동차 목록을 검색합니다. (JQuery는 알아야 할 훌륭한 JavaScript 프레임 워크입니다. JavaScript의 개발이 훨씬 쉽게 개발됩니다. 문서는 매우 좋습니다).

그 중 일부가 이해되기를 바랍니다.

다음은 태그 라이브러리 나 외부 종속성이없는 JSP의 작동, 컷 및 페이스트 답변입니다. 모델이있는 맵은 하드 코딩되었지만 문제를 제기해서는 안됩니다.

추가 된 JSP가 가독성을 향상시키지 않기 때문에이 답변을 이전 답변과 분리했습니다. 그리고 '실생활'에서 나는 모든 내장 된 논리로 JSP에 부담을주지 않고 어딘가에 수업에 넣었습니다. 또는 태그를 사용하십시오.

"첫 번째"물건은 생성 된 코드에서 "Superfluos를 방지하는 것"입니다. foreach dos를 사용하면 요소의 양에 대한 지식을 제공하지 않으므로 마지막으로 확인하십시오. 또한 첫 번째 요소 처리를 건너 뛰고 마지막 ","나중에 빌더 길이를 1 씩 줄임으로써 "마지막"을 벗길 수 있습니다.

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<%@page import="java.util.Map"%>
<%@page import="java.util.TreeMap"%>
<%@page import="java.util.Arrays"%>
<%@page import="java.util.Collection"%>
<%@page import="java.util.List"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Challenge</title>
</head>
<body onload="setModels()">
<% // You would get your map some other way.
    Map<String,List<String>> map = new TreeMap<String,List<String>>();
    map.put("porsche", Arrays.asList(new String[]{"911", "Carrera"}));
    map.put("mercedes", Arrays.asList(new String[]{"foo", "bar"}));
%>

<%! // You may wish to put this in a class
  public String modelsToJavascriptList(Collection<String> items) {
    StringBuilder builder = new StringBuilder();
    builder.append('[');
    boolean first = true;
    for (String item : items) {
        if (!first) {
          builder.append(',');
        } else {
          first = false;
        }
        builder.append('\'').append(item).append('\'');
    }
    builder.append(']');
    return builder.toString();
  }

  public String mfMapToString(Map<String,List<String>> mfmap) {
    StringBuilder builder = new StringBuilder();
    builder.append('{');
    boolean first = true;
    for (String mf : mfmap.keySet()) {
      if (!first) {
          builder.append(',');
      } else {
          first = false;
      }
      builder.append('\'').append(mf).append('\'');
      builder.append(" : ");
      builder.append( modelsToJavascriptList(mfmap.get(mf)) );
    }
    builder.append("};");
    return builder.toString();
  }
%>

<script>
var modelsPerManufacturer =<%= mfMapToString(map) %>
  function setSelectOptionsForModels(modelArray) {
    var selectBox = document.myForm.models;

    for (i = selectBox.length - 1; i>= 0; i--) {
    // Bottom-up for less flicker
    selectBox.remove(i);
    }

    for (i = 0; i< modelArray.length; i++) {
     var text = modelArray[i];
      var opt = new Option(text,text, false, false);
      selectBox.add(opt);
    }
  }

  function setModels() {
    var index = document.myForm.manufacturer.selectedIndex;
    if (index == -1) {
    return;
    }

    var manufacturerOption = document.myForm.manufacturer.options[index];
    if (!manufacturerOption) {
      // Strange, the form does not have an option with given index.
      return;
    }
    manufacturer = manufacturerOption.value;

    var modelsForManufacturer = modelsPerManufacturer[manufacturer];
    if (!modelsForManufacturer) {
      // This modelsForManufacturer is not in the modelsPerManufacturer map
      return; // or alert
    }
    setSelectOptionsForModels(modelsForManufacturer);
  }

  function modelSelected() {
    var index = document.myForm.models.selectedIndex;
    if (index == -1) {
      return;
    }
    alert("You selected " + document.myForm.models.options[index].value);
  }
  </script>
  <form name="myForm">
    <select onchange="setModels()" id="manufacturer" size="5">
      <% boolean first = true;
         for (String mf : map.keySet()) { %>
          <option value="<%= mf %>" <%= first ? "SELECTED" : "" %>><%= mf %></option>
      <%   first = false;
         } %>
    </select>

    <select onChange="modelSelected()" id="models" size="5">
      <!-- Filled dynamically by setModels -->
    </select>
  </form>

</body>
</html>

프로토 타입을 사용하는 것은 어떻습니까? 먼저, 선택 카테고리 상자 :

<SELECT onchange="changeCategory(this.options[this.selectedIndex].value); return false;">
   <OPTION value="#categoryID#">#category#</OPTION>
   ...

그런 다음 각 하위 범주마다 다른 선택 상자를 출력합니다.

<SELECT name="myFormVar" class="categorySelect">
...                                        

ChangeCategory javaScript 함수는 클래스 카테고리 Select를 사용하여 모든 SELECTS를 비활성화 한 다음 현재 CategoryID의 경우 만 활성화합니다.

// Hide all category select boxes except the new one
function changeCategory(categoryID) {

   $$("select.categorySelect").each(function (select) {
      select.hide();
      select.disable();
   });

   $(categoryID).show();
   $(categoryID).enable();
}

프로토 타입에서 이와 같이 숨기거나 비활성화하면 페이지에 숨어있을뿐만 아니라 해당 양식 변수가 게시되지 않도록합니다. 따라서 N이 동일한 형식 변수 이름 (MyFormVar)으로 선택되어 있더라도 활성 하나의 게시물 만 선택합니다.

오래 전에 나는 비슷한 것에 대해 생각했다.

jQuery와 Texotela 애드온을 사용하는 것은 그다지 어렵지 않았습니다.

먼저 위에서 언급 한지도와 같은 데이터 구조가 있습니다.

var map = {
   'porsche': [ 'boxter', '911', 'carrera' ],
   'fiat': ['punto', 'uno']
}; 

HTML은 다음과 비슷하게보아야합니다.

<select size="4" id="manufacturers">
</select>
<select size="4" id="models">
</select>

그런 다음 첫 번째 콤보를 다음과 같은 jQuery 코드로 채 웁니다.

$(document).ready(
  function() {
    $("#bronsysteem").change( manufacturerSelected() );
  } );
);

OnChange 이벤트에 등록 된 콜백 인 ManufacturerSelected

function manufacturerSelected() {
  newSelection = $("#manufacturers").selectedValues();
  if (newSelection.length != 1) {
    alert("Expected a selection!");
    return; 
  }
  newSelection = newSelection[0];
  fillModels(newSelection);     
}

function fillModels(manufacterer) {
    var models = map[manufacturer];

    $("models").removeOption(/./); // Empty combo

    for(modelId in models) {
       model = models[modelId];
       $("models").addOption(model,model); // Value, Text
    }
}

이것은 트릭을 수행해야합니다.

거기에 구문 오류가있을 수 있습니다. 사용 사례를 반영하기 위해 코드를 편집했으며 많이 제거해야했습니다.

이것이 도움이된다면 의견을 감사하게 생각합니다.

내 이전 게시물에 대한 추가 기능으로;지도를 반복하는 JSP에 스크립트 태그를 넣을 수 있습니다.맵 반복에 대한 예는 다음에서 찾을 수 있습니다. Struts의 지도.

(양식 제출에 관심이 없다면) 달성하고 싶은 것은 다음과 같습니다.

<script>
  var map = {
  <logic:iterate id="entry" name="myForm" property="myMap">
     '<bean:write name=" user" property="key"/>' : [
     <logic:iterate id="model" name="entry" property="value">
       '<bean:write name=" model" property="name"/>' ,
     </logic:iterate>
     ] ,
 </logic:iterate>
  };
</script>

여전히 방지하고 싶은 불필요한 ""가 있지만 이것이 효과가 있다고 생각합니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top