2008-10-01 2 views
1

Хорошо, вот один для гуру Java/JavaScript:Dynamicaly заселения выпадающего со значениями из карты на основании того, что выбрано в другом выпадающем списке

В моем приложении, один из контроллеров передает TreeMap на это JSP. Эта карта имеет имена производителей автомобилей в качестве ключей и списки объектов автомобилей в качестве значений. Эти объекты автомобилей простые бобы, содержащие название автомобиля, идентификатор, год выпуска и т.д. Таким образом, карта выглядит примерно так (это просто пример, чтобы уточнить вещи немного):

Ключ: Porsche
Значение: список, содержащий три объекта автомобилей (например, 911, Carrera, Boxter с их респектабельными годами производства и идентификаторы)
Ключ: Fiat
Значение: Список, содержащий два объекта для автомобилей (например, Punto и Uno)
и т. Д. ..

Теперь, в моем JSP у меня есть два comboboxes. Нужно получить список автопроизводителей (ключи от карты - эта часть, которую я знаю, как это сделать), а другой должен изменить динамическое значение, чтобы отображать названия автомобилей, когда пользователь выбирает определенного производителя из первого combobox , Так, например, пользователь выбирает «Porsche» в первом combobox, а второй сразу отображает «911, Carrera, Boxter» ...

Проведя несколько дней, пытаясь выяснить, как это сделать, Я готов признать поражение. Я пробовал много разных вещей, но каждый раз, когда я ударялся о стену, где-то там по пути. Может ли кто-нибудь предложить, как я должен подойти к этому? Да, я новичок JavaScript, если кто-нибудь задавался вопросом ...

EDIT: Я retagged это как код-вызов. Престижность любому, кто решает этот, без использования каких-либо JavaScript-фреймворков (например, JQuery).

ответ

2

Ну во всяком случае, как я сказал, я, наконец, удалось сделать это сам, так вот мой ответ ...

я получаю карту от моего контроллера, как это (я использую Spring, не знаю, как это работает с другими системами):

<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]); 
    }  
} 

1

Вы используете Struts?

Для этого вам понадобится 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. Документация очень хорошая).

Я надеюсь, что некоторые из них имеют смысл?

+0

Спасибо за ваш ответ, Фил. На самом деле, я использую Spring. Хотя ваш ответ хороший, мне все равно хотелось бы услышать другие мнения :-) – Sandman 2008-10-01 09:34:47

0

Как насчет чего-то подобного, используя прототип? Во-первых, ваш выбор коробка категорий:

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

Затем вы выводите N различных полей выбора, один для каждой из подкатегорий:

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

Ваш changeCategory Javascript функция отключает все выбирает с классом categorySelect , а затем включает только один для вашего текущего идентификатора категории.

// 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, выбирается с тем же именем переменной FORM (myFormVar), только активные сообщения.

+0

Если я это правильно понимаю, каждый раз, когда производитель или производитель автомобилей добавляется или удаляется с карты, мне придется добавить или удалить соответствующий тег select в JSP. Поскольку я получаю эту Карту с веб-службы поставщика, у меня нет способа узнать, сколько элементов может иметь Карта. – Sandman 2008-10-02 07:20:49

+0

И я до сих пор не знаю, как получить имена машин. Имя автомобиля является объектом String в объекте Car, которое хранится в списке, который хранится как значение на карте. Ух ... поговорите о сложном ... – Sandman 2008-10-02 07:25:03

0

Не так давно я думал о чем-то подобном.

Использование 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

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 
    } 
} 

Это должно сделать трюк.

Обратите внимание, что там могут быть ошибки синтаксиса; Я отредактировал свой код, чтобы отразить ваш прецедент, и пришлось довольно часто снимать .

Если это поможет, то я ценю комментарий.

+0

Прежде всего, спасибо за ваш ответ, extraneon. Я буду использовать его, если не найду другого пути. Однако здесь есть два вопроса. Первый заключается в том, что я не делаю этого для своего личного проекта, но как часть более крупного корпоративного приложения для компании, в которой я сейчас работаю. Из-за этого, – Sandman 2008-10-04 10:19:06

0

В качестве дополнения к моему предыдущему сообщению; Вы можете поместить тег сценария в свой JSP, где вы перебираете свою карту. Пример об итерации по картам можно найти в Maps in 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> 

У вас еще есть некоторые superfuous «» которые вы могли бы пожелать, чтобы предотвратить, но Я думаю, что это должно сделать трюк.

3

Мне просто нравится вызов.

Нет jQuery, просто javascript, протестирован на Safari.

Я хотел бы добавить следующие замечания заранее:

  • Это faily долго из-за ошибки проверки .
  • Изготовлены две части; первого узел сценария с картой и содержанием manufacterer ВЫБРАТЬ
  • работают на моей машине (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> 
1

Вот рабочий ответ на вырезку и вставку в jsp без каких-либо библиотек тегов или внешних зависимостей. Карта с моделями жестко закодирована, но не должна создавать никаких проблем.

Я отделил этот ответ от своего предыдущего ответа, поскольку добавленный JSP не улучшает читаемость. И в «реальной жизни» я бы не стал обременять мою JSP всей встроенной логикой, но поместил ее в какой-то класс. Или используйте теги.

Все эти «первые» вещи предназначены для предотвращения суперфлюоса «,» в сгенерированном коде. Использование foreach не дает вам никаких знаний о количестве элементов, поэтому вы проверяете их на последний. Вы также можете пропустить обработку первого элемента и полосы последнего «» потом за счет уменьшения длины строителем 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> 
Смежные вопросы