Динамический select Вот решение: HTML: <html> <head> <meta http-equiv="Content-Language" content="ru"> <meta http-equiv="Content-Type" content="text/html; charset=windows-1251"> <script type="text/javascript"> [js]function syncList() { } //Метод sync() - принимает список из значений атрибутов id элементов SELECT, образующих связанный список и запускает их синхронизацию syncList.prototype.sync = function() { //Перебираем аргументы (id элементов SELECT) и назначаем событиям onChange селектов, с соответствующими id, функцию-обработчик. //В качестве обработчика выступает второй метод объекта syncList - _sync (напрямую его вызывать не нужно) //Обработчик назначается всем элементам SELECT кроме последнего в списке аргументов, т.к. последний не влияет ни на какой другой элемент SELECT и с ним не нужно синхронизироваться. for (var i=0; i < arguments.length-1; i++) document.getElementById(arguments).onchange = (function (o,id1,id2){return function(){o._sync(id1,id2);};})(this, arguments, arguments[i+1]); document.getElementById(arguments[0]).onchange();//запускаем обработчик onchange первого селекта, чтобы при загрузке страницы заполнить дочерние селекты значениями. } //служебный метод _sync - срабатывает при смене выбранного элемента в текущем (старшем) элементе SELECT (по его событию onChange) и изменяет содержимое зависимого селекта на основании значения выбранного в старшем селекте. syncList.prototype._sync = function (firstSelectId, secondSelectId) { var firstSelect = document.getElementById(firstSelectId); var secondSelect = document.getElementById(secondSelectId); secondSelect.length = 0; //обнуляем второй (подчиненный) SELECT if (firstSelect.length>0)//если первый (старший) SELECT не пуст { //из свойства dataList, с данными для заполнения подчиненных селектов, берем ту часть данных, которая соответствует именно значению элемента, //выбранного в первом селекте, и определяет содержимое подчиненного элемента SELECT. var optionValue = firstSelect.options[ firstSelect.selectedIndex==-1 ? 0 : firstSelect.selectedIndex].value; var optionData = this.dataList[optionValue]; if (!optionData) optionData = this.dataList[parseInt(optionValue)]; //заполняем второй (подчиненный) селект значениями (создаем элементы option) for (var key in optionData || null) secondSelect.options[secondSelect.length] = new Option(optionData[key], key); //если в старшем SELECT-е нет выделенного пункта, выделяем первый if (firstSelect.selectedIndex == -1) setTimeout( function(){ firstSelect.options[0].selected = true;}, 1 ); //если во втором списке нет выделенного пункта, выделяем первый его пункт if (secondSelect.length>0) setTimeout( function(){ secondSelect.options[0].selected = true;}, 1 ); } //если второй (подчиненный) селект имеет в свою очередь свои подчиненные селекты (те, для которых он главный), //то запускаем его обработчик onchange, чтобы изменить его подчиненные селекты secondSelect.onchange && secondSelect.onchange(); };[/js] HTML: </script> </head> <body> <select size="1" id="action" name="action"> <option value="no_action">Выберите действие</option> <option value="01">01</option> <option value="02">02</option> <option value="03">03</option> </select> <select size="1" id="ok" name="ok"></select> <script type="text/javascript"> [js] var syncList1 = new syncList; syncList1.dataList = { '01': { 'n':'Нет', // Значение:надпись в селекте 'y':'Да' }, 'no_action': { 'no_action':'----------' }, '02': { '02.1':'02.1', '02.2':'02.2', '02.3':'02.3' }, '03': { '10':'10', '90':'90', '100':'100' } }; syncList1.sync("action","ok"); // Синхронизация списков [/js] HTML: </script> </body> </html>
Это пример для двух селектов... можно сделать и три Хочу обратить внимание, что второй JS скрипт выполняется ПОСЛЕ формы с select`ами
Nemo Замечательный пример, но на старой Опере (7) глючит. Она зачем-то приводит строковые индексы, которые выглядят как числа, к числовому виду. Соответственно вместо индексов типа "01", "02" в массиве dataList появляются индексы 1, 2 и т. д. Помогает патчик: вместо [js]var optionData = this.dataList[ firstSelect.options[firstSelect.selectedIndex==-1 ? 0 : firstSelect.selectedIndex].value ];[/js] пишем [js]var optionValue = firstSelect.options[ firstSelect.selectedIndex==-1 ? 0 : firstSelect.selectedIndex].value; var optionData = this.dataList[optionValue]; if (!optionData) optionData = this.dataList[parseInt(optionValue)];[/js] и работает уже на всех браузерах.
У меня такой вопрос: Можно-ли в данном варианте сделать так чтобы при загрузке страницы уже были выбраны какие-нибудь значения ? Код (Text): var syncList1 = new syncList; syncList1.dataList = { '01': { 'n':'Нет', // Значение:надпись в селекте 'y':'Да' }, 'no_action': { 'no_action':'----------' }, '02': { '02.1':'02.1':'selected', - К примеру '02.2':'02.2', '02.3':'02.3' }, '03': { '10':'10', '90':'90', '100':'100' } }; syncList1.sync("action","ok"); // Синхронизация списков
Вот скрипт: [js]function syncList(){} syncList.prototype.sync = function() { for (var i=0; i < arguments.length-1; i++) document.getElementById(arguments).onchange = (function (o,id1,id2){return function(){o._sync(id1,id2);};})(this, arguments, arguments[i+1]); document.getElementById(arguments[0]).onchange(); } syncList.prototype._sync = function (firstSelectId, secondSelectId) { var firstSelect = document.getElementById(firstSelectId); var secondSelect = document.getElementById(secondSelectId); secondSelect.length = 0; if (firstSelect.length>0) { var optionValue = firstSelect.options[ firstSelect.selectedIndex==-1 ? 0 : firstSelect.selectedIndex].value; var optionData = this.dataList[optionValue]; if (!optionData) optionData = this.dataList[parseInt(optionValue)]; for (var key in optionData || null) secondSelect.options[secondSelect.length] = new Option(optionData[key], key); if (firstSelect.selectedIndex == -1) setTimeout( function(){ firstSelect.options[0].selected = true;}, 1 ); if (secondSelect.length>0) setTimeout( function(){ secondSelect.options[0].selected = true;}, 1 ); secondSelect.onchange && secondSelect.onchange(); } };[/js] HTML: <select name="step1" size="7" id="List1"> <option value=1>Комплектующие</option> </select> <select name="step2" size="7" id="List2"></select> <select name="step3" size="7" id="List3"></select> <script type="text/javascript"> var syncList1 = new syncList; syncList1.dataList = { '1':{ '2':'Процессоры', '3':'Материнки', '4':'Оперативка', '5':'Видео карты', '6':'Жёсткие диски', '7':'СД Приводы', '8':'Звуковые карты', '9':'Сетевые карты', '10':'Корпуса', '11':'Блоки питания' }, '2':{ '12':'Pentium 4', '13':'Pentium D', '14':'Core 2 Duo', '15':'Core 2 Quad', '16':'Celeron D', '17':'Athlon XP', '18':'Athlon 62 x2' } }; syncList1.sync("List1","List2","List3"); </script>
Как к примеру сделать это: HTML: '15':'Core 2 Quad':'selected', - или как то по другому ... Я в javascript не силён. Если не сложно скажи ... или хотя бы скажи где копать [js]var optionValue = firstSelect.options[ firstSelect.selectedIndex==-1 ? 0 : firstSelect.selectedIndex : firstSelect.selectedIndex==selected].value; <- бред [/js]
а вот ещё вариант. мне кажется он более удобен в использовании Код (Text): <form name="modelform"> <td valign=top><select class=select onchange="modelform_rebuild(this.options[this.selectedIndex].value)"><option value="0">--- <option value="30">Toyota <option value="31">Nissan <option value="33">Mitsubishi <option value="34">Honda <option value="35">Mazda <option value="32">Subaru <option value="36">Suzuki <option value="37">Isuzu </select> <select name="models_id" class=select><option value="0">---</select> <script language="javascript"> function modelform_rebuild(b){ switch (b) { case '0': with (modelform.models_id) { options.length = 0; options[0] = new Option('---', '0'); selectedIndex = 0; }; break; case '30': with (modelform.models_id) { options.length= 0; options[0]= new Option('---','0'); options[1]= new Option('Allex','479'); options[2]= new Option('Allion','424'); options[3]= new Option('Alphard','489'); selectedIndex=0; }; break; case '31': with (document.modelform.models_id) { options.length= 0; options[0]= new Option('---','0'); options[1]= new Option('180SX','630'); options[2]= new Option('Ad Wagon','637'); options[3]= new Option('Atlas','1033'); options[4]= new Option('Avenir','638'); options[5]= new Option('Bassara','607'); selectedIndex=0; }; break; case '33': with (document.modelform.models_id) { options.length= 0; options[0]= new Option('---','0'); options[1]= new Option('Airtrek','862'); options[2]= new Option('Aspire','885'); options[3]= new Option('Bravo','855'); selectedIndex=0; }; break; case '34': with (document.modelform.models_id) { options.length= 0; options[0]= new Option('---','0'); options[1]= new Option('Accord','744'); options[2]= new Option('Accord Coupe','729'); options[3]= new Option('Accord Inspire','745'); selectedIndex=0; }; break; case '35': with (document.modelform.models_id) { options.length= 0; options[0]= new Option('---','0'); options[1]= new Option('Atenza Sedan','822'); options[2]= new Option('Atenza Sport','823'); options[3]= new Option('Atenza Sport Wagon','821'); selectedIndex=0; }; break; case '32': with (document.modelform.models_id) { options.length= 0; options[0]= new Option('---','0'); options[1]= new Option('Alcyone','573'); selectedIndex=0; }; break; case '36': with (document.modelform.models_id) { options.length= 0; options[0]= new Option('---','0'); options[1]= new Option('Aerio Sedan','524'); options[2]= new Option('Aerio Wagon','533'); selectedIndex=0; }; break; case '37': with (document.modelform.models_id) { options.length= 0; options[0]= new Option('---','0'); options[1]= new Option('Aska','758'); options[2]= new Option('Bighorn','766'); options[3]= new Option('Elf','951'); selectedIndex=0; }; break; } } </script> тут и выбрать можно какую-либо строку.
Тут всё дело в кривоватом рендеринге Оперы. Как ни странно, лечение заключается в том, что надо скрыть а затем показать второй селект Код (Text): function modelform_rebuild(b){ ... ... modelform.models_id.style.display = 'none'; modelform.models_id.style.display = ''; }
Nemo привет слушай а как сделать так чтобы Select из БД считывал значения я тольео для 1ого Selecta освоил: Код (Text): <select name="category"> <?php if ($res = mysql_query("SELECT * FROM `categories` ORDER BY `name`")) { while ($row = mysql_fetch_assoc($res)) { echo '<option value="'.$row['id'].'">'.$row['name'].'</option>'; } } ?> </select> и мне надо чтобы 2ой Select обновлялся при выборе 1ого. Буду благодарен за помощь
Есть у меня небольшая формочка, сформированная на PHP. Её HTML вид может выглядеть вот так Код (Text): <form method=Post action=/1/admin.php enctype="multipart/form-data" name="setevent"> <input type="hidden" name="submitted" value=false;> <table> <tr> <td> Название события </td> <td> <input type="text" name="event_name"> </td> </tr> <tr> <td> Место проведения </td> <td> <input type="text" name="country"> </td> </tr> <tr> <td> Изображение </td> <td> <input type="file", name="image"> </td> </tr> </table> Дата проведения <select name="day" size="1"> <script language="JavaScript"> for(var i=1;i<=31;i++)document.write("<option value="+i+">"+i+"</option>"); </script> </select> <select name="month" size="1" onchange="yearchange()"> <option value="1">январь</option> <option value="2">февраль</option> <option value="3">март</option> <option value="4">апрель</option> <option value="5">май</option> <option value="6">июнь</option> <option value="7">июль</option> <option value="8">август</option> <option value="9">сентябрь</option> <option value="10">октябрь</option> <option value="11">ноябрь</option> <option value="12">декабрь</option> </select> <input type="text" name="year" onchange="yearchange()">года <br> Содержание <br> <Textarea name="content" rows="40" cols="40"> </Textarea> <br> Тип события <select name="type_event" size="1"> <option value=Обувь>Обувь</option><option value=Одежда>Одежда</option><option value=Авто>Авто</option><option value=Спорт>Спорт</option><option value=Мото>Мото</option><option value=Здоровье>Здоровье</option><option value=Бизнес>Бизнес</option></select> <br> <input type="button" value="Сохранить" onclick="setevent.submitted=true;yearchange();"> </form> В ней есть селекты с выбором дня и месяца года. Для того, чтобы дней в месяце всегда было столько сколько нужно (с учётом високосных годов) написал следующий функции на JS Код (Text): <script Language="Javascript"> function yearchange(){ var days=new Array(31,28,31,30,31,30,31,31,30,31,30,31); if(setevent.submitted||(setevent.month.value==2)){ if(!isFinite(setevent.year.value)||setevent.year.value<0){alert("Введите правильно год"); return;}else{if(!(year.value%4))days[1]=29;}}} if(setevent.day.options.length>0)while(setevent.day.options.length>0)setevent.day.options.remove(setevent.day.options.length-1); for(var i=1;i<days[setevent.month.value-1];i++){var option=document.CreateElement("OPTION"); option.text=i; option.value=i; setevent.day.options.add(option); if(setevent.submitted)setevent.submit;} </script> Проблема в том, что на неправильные символы в инпуте для года функция, как ей и положено ругается, а вот заставить её менять количество дней в соответствующем селекте у меня так и не получилось. Не подскажете, почему?
Nemo Так что ж это за динамический сэлект если в syncList1.dataList надо помещать все значения, а если их там 10000?
[js] <!--это список регионов по изменению которого в таком же списке только с id=city обновляются города соответственно id выбранного региона, значение которого находиться естественно в value optionа --> <select name="region" id="region" onChange="UpdateSelect('city', this.value);"> <script type="text/javascript"> //Далее следуют функции для ассинхронного обмена - реального динамического селекта //Эта функция создает объект которым пользуется браузер для посылания скрипту ассинхронного запроса function CreateXMLHttpRequestObject() { var xmlHttp; try { xmlHttp = new XMLHttpRequest(); } catch(e) { var XMLHttpVersions = new Array('MSXML2.XMLHTTP.6.0', 'MSXML2.XMLHTTP.5.0', 'MSXML2.XMLHTTP.4.0', 'MSXML2.XMLHTTP.3.0', 'MSXML2.XMLHTTP', 'Microsoft.XMLHTTP'); for(var i=0; i<XMLHttpVersions.length && !xmlHttp; i++) { try { xmlHttp = new ActiveXObject(XMLHttpVersions); } catch(e) {} } } if(!xmlHttp) { alert("Ваш браузер не поддерживает ассинхронную передачу"); } else { return xmlHttp; } } //Создается ранее упомянутый объект //Обратите внимание - он с глобальной областью видимости var xmlHttp = CreateXMLHttpRequestObject(); //Эта функция очишает список по его id и присваивает ему значение по улолчанию function ClearSelect(select_id) { var selElement = document.getElementById(select_id); selElement.options.length = 0; selElement.options[selElement.options.length] = new Option("значение по умолчанию", 0, false, false); } //Это самая главная функция //Она настраивает параметры ассинхронного запроса: xmlHttp.open //определяет функцию обработчик событий изменения состояния запроса:xmlHttp.onreadystatechange //ну и посылает запрос xmlHttp.send function UpdateSelect(select_id, parent_select_value) { if(!xmlHttp) { return false; } if(parent_select_value == 0) { if(select_id == 'city') { ClearSelect('city'); } else { ClearSelect('region'); ClearSelect('city'); } return true; } try { switch (select_id) { case 'city': var uri = "./userlive.php?r=" + parent_select_value; break; case 'region': var uri = "./userlive.php?s=" + parent_select_value; break; default: return false; break; } xmlHttp.open("GET", uri, true); xmlHttp.onreadystatechange = function() { if(xmlHttp.readyState == 4) { if(xmlHttp.status == 200) { try { ProcessXMLResponse(select_id); } catch(e) { ClearSelect(select_id); } } else { ClearSelect(select_id); } } } xmlHttp.send(null); } catch(e) { ClearSelect(select_id); return false; } return true; } //Эта функция вызывается обработчиком события изменения состояния запроса //При xmlHttp.readyState == 4 браузер получил ответ //Фактически эта функция получает xml обект и парсит его генерируя новые option - ы в select - е //В данном случае скрипт userlive.php возращает xml документ такого характера //<?xml ....и все такое //<cities> //<city> //<id>5</id> //<name>Москва</name> //</city> //******Остальная куча городов //</cities> function ProcessXMLResponse(select_id) { var xmlResponse = xmlHttp.responseXML; if(!xmlResponse || !xmlResponse.documentElement) { throw("Ошибка на сервере"); } var rootNodeName = xmlResponse.documentElement.nodeName; if(rootNodeName == "parsererror") { throw("Ошибка на сервере"); } xmlRoot = xmlResponse.documentElement; idArray = xmlRoot.getElementsByTagName("id"); nameArray = xmlRoot.getElementsByTagName("name"); var selElement = document.getElementById(select_id); selElement.options.length = 0; selElement.disabled = false; if(idArray.length<1) { if(select_id == 'city') { ClearSelect('city'); } else { ClearSelect('region'); ClearSelect('city'); } return; } for(var i = 0; i<idArray.length; i++) { selElement.options[selElement.options.length] = new Option(nameArray.item(i).firstChild.data, idArray.item(i).firstChild.data, false, false); } } </script> [/js]