Вложения опций в выпадающем списке/select

Я создал элемент управления С# DropDownList клиента, который может отображать его содержимое, являются optgroups (не с нуля, я редактировал какой-то код, найденный в Интернете, хотя я точно понимаю, что он делает), и он отлично работает.

Однако теперь я столкнулся с ситуацией, когда мне нужно иметь два уровня отступов в моем выпадающем меню, т.е.

<select>
    <optgroup label="Level One">
     <option> A.1 </option>
     <optgroup label="Level Two">
      <option> A.B.1 </option>
     </optgroup>
     <option> A.2 </option>
    </optgroup>
</select>

Однако, насколько мне известно, это будет выглядеть как обычные optgroups.

Есть ли способ создать это вложенное поведение?

Ответ 1

Хорошо, если кто-нибудь еще прочтет это: лучший вариант - добавить четыре &nbsp; на каждый дополнительный уровень отступов, казалось бы!

так:

<select>
 <optgroup label="Level One">
  <option> A.1 </option>
  <optgroup label="&nbsp;&nbsp;&nbsp;&nbsp;Level Two">
   <option>&nbsp;&nbsp;&nbsp;&nbsp; A.B.1 </option>
  </optgroup>
  <option> A.2 </option>
 </optgroup>
</select>

Ответ 2

Спецификация HTML здесь действительно сломана. Он должен позволять вложенным группам пользователей и рекомендовать пользовательские агенты отображать их как вложенные меню. Вместо этого разрешен только один уровень группы opt. Однако они должны сказать следующее по этому вопросу:

Примечание. Разработчикам рекомендуется, чтобы будущие версии HTML могли расширить механизм группировки, чтобы разрешить вложенные группы (т.е. Элементы OPTGROUP могут входить). Это позволит авторам представлять более богатую иерархию вариантов.

И пользовательские агенты могут начать использовать подменю для рендеринга optgoups вместо отображения титров перед первым элементом элемента в optgroup, как сейчас.

Ответ 3

Это просто отлично, но если вы добавите опцию, ведьма не в optgroup, она становится глючной.

<select>
    <optgroup label="Level One">
        <option> A.1 </option>
        <optgroup label="nbsp;nbsp;nbsp;nbsp;Level Two">
            <option>nbsp;nbsp;nbsp;nbsp; A.B.1 </option>
        </optgroup>
        <option> A.2 </option>
    </optgroup>
    <option> A </option>
</select>

Было бы намного лучше, если бы вы сразу же использовали css и close optgroup:

<select>
    <optgroup label="Level One"></optgroup>
    <option style="padding-left:15px"> A.1 </option>
    <optgroup label="Level Two" style="padding-left:15px"></optgroup>
    <option style="padding-left:30px"> A.B.1 </option>    
    <option style="padding-left:15px"> A.2 </option>
    <option> A </option>
</select>

Ответ 4

<style>
    .NestedSelect{display: inline-block; height: 100px; border: 1px Black solid; overflow-y: scroll;}
    .NestedSelect label{display: block; cursor: pointer;}
    .NestedSelect label:hover{background-color: #0092ff; color: White;}
    .NestedSelect input[type="radio"]{display: none;}
    .NestedSelect input[type="radio"] + span{display: block; padding-left: 0px; padding-right: 5px;}
    .NestedSelect input[type="radio"]:checked + span{background-color: Black; color: White;}
    .NestedSelect div{margin-left: 15px; border-left: 1px Black solid;}
    .NestedSelect label > span:before{content: '- ';}
</style>

<div class="NestedSelect">
    <label><input type="radio" name="MySelectInputName"><span>Fruit</span></label>
    <div>
        <label><input type="radio" name="MySelectInputName"><span>Apple</span></label>
        <label><input type="radio" name="MySelectInputName"><span>Banana</span></label>
        <label><input type="radio" name="MySelectInputName"><span>Orange</span></label>
    </div>

    <label><input type="radio" name="MySelectInputName"><span>Drink</span></label>
    <div>
        <label><input type="radio" name="MySelectInputName"><span>Water</span></label>

        <label><input type="radio" name="MySelectInputName"><span>Soft</span></label>
        <div>
            <label><input type="radio" name="MySelectInputName"><span>Cola</span></label>
            <label><input type="radio" name="MySelectInputName"><span>Soda</span></label>
            <label><input type="radio" name="MySelectInputName"><span>Lemonade</span></label>
        </div>

        <label><input type="radio" name="MySelectInputName"><span>Hard</span></label>
        <div>
            <label><input type="radio" name="MySelectInputName"><span>Bear</span></label>
            <label><input type="radio" name="MySelectInputName"><span>Whisky</span></label>
            <label><input type="radio" name="MySelectInputName"><span>Vodka</span></label>
            <label><input type="radio" name="MySelectInputName"><span>Gin</span></label>
        </div>
    </div>
</div>

Ответ 5

Я думаю, что если у вас есть что-то структурированное и сложное, вы можете рассмотреть что-то другое, кроме одного раскрывающегося списка.

Ответ 6

Я знаю, что это было довольно давно, однако у меня есть немного дополнительного, чтобы добавить:

Это невозможно в HTML5 или любых предыдущих спецификациях, а также не предлагается в HTML5.1. Я отправил запрос в список рассылки public-html-comments, но мы увидим, если что-нибудь из этого получится.

Несмотря на это, пока это невозможно с помощью <select>, вы можете добиться аналогичного эффекта со следующим HTML, плюс некоторый CSS для красивости:

<ul>
    <li>
        <input type="radio" name="location" value="0" id="loc_0" />
        <label for="loc_0">United States</label>

        <ul>
            <li>
                Northeast

                <ul>
                    <li>
                        <input type="radio" name="location" value="1" id="loc_1" />
                        <label for="loc_1">New Hampshire</label>
                    </li>

                    <li>
                        <input type="radio" name="location" value="2" id="loc_2" />
                        <label for="loc_2">Vermont</label>
                    </li>

                    <li>
                        <input type="radio" name="location" value="3" id="loc_3" />
                        <label for="loc_3">Maine</label>
                    </li>
                </ul>
            </li>

            <li>
                Southeast

                <ul>
                    <li>
                        <input type="radio" name="location" value="4" id="loc_4" />
                        <label for="loc_4">Georgia</label>
                    </li>

                    <li>
                        <input type="radio" name="location" value="5" id="loc_5" />
                        <label for="loc_5">Alabama</label>
                    </li>
                </ul>
            </li>
        </ul>
    </li>

    <li>
        <input type="radio" name="location" value="6" id="loc_6" />
        <label for="loc_6">Canada</label>

        <ul>
            <li>
                <input type="radio" name="location" value="7" id="loc_7" />
                <label for="loc_7">Ontario</label>
            </li>

            <li>
                <input type="radio" name="location" value="8" id="loc_8" />
                <label for="loc_8">Quebec</label>
            </li>

            <li>
                <input type="radio" name="location" value="9" id="loc_9" />
                <label for="loc_9">Manitoba</label>
            </li>
        </ul>
    </li>
</ul>

В качестве дополнительного дополнительного преимущества это также означает, что вы можете разрешить выбор самих <optgroups>. Это может быть полезно, если у вас есть, например, вложенные категории, в которых категории относятся к деталям, и вы хотите разрешить пользователям выбирать выше в иерархии.

Все это будет работать без JavaScript, однако вы можете добавить некоторые, чтобы скрыть радиокнопки, а затем изменить цвет фона выбранного элемента или что-то в этом роде.

Помните, что это далеко не идеальное решение, но если вам абсолютно необходим вложенный выбор с разумной совместимостью между браузерами, это, вероятно, так близко, как вы собираетесь получить.

Ответ 7

Мне нужно было чистое и легкое решение (так что не jQuery и так далее), которое будет выглядеть точно так же, как обычный HTML, также будет продолжать работать, когда будет установлен только простой HTML (поэтому javascript только улучшит его), что позволит начиная с букв (включая национальные буквы UTF-8), если это возможно, где он не добавляет лишнего веса. Он также должен работать быстро в очень медленных браузерах (подумайте, что rPi - поэтому желательно, чтобы javascript не выполнялся после загрузки страницы).

В firefox он использует идентификатор CSS и, таким образом, позволяет выполнять поиск по буквам, а в других браузерах он будет использовать &nbsp; prepending (но там он не поддерживает быстрый поиск по буквам). Во всяком случае, я доволен результатами.

Вы можете попробовать его в действии здесь

Это происходит следующим образом:

CSS

.i0 { }
.i1 { margin-left: 1em; }
.i2 { margin-left: 2em; }
.i3 { margin-left: 3em; }
.i4 { margin-left: 4em; }
.i5 { margin-left: 5em; }

HTML (класс "i1", "i2" и т.д. обозначают уровень идентификации):

<form action="/filter/" method="get">
<select name="gdje" id="gdje">
<option value=1 class="i0">Svugdje</option>
<option value=177 class="i1">Bosna i Hercegovina</option>
<option value=190 class="i2">Babin Do</option>  
<option value=258 class="i2">Banja Luka</option>
<option value=181 class="i2">Tuzla</option>
<option value=307 class="i1">Crna Gora</option>
<option value=308 class="i2">Podgorica</option>
<option value=2 SELECTED class="i1">Hrvatska</option>
<option value=5 class="i2">Bjelovarsko-bilogorska županija</option>
<option value=147 class="i3">Bjelovar</option>
<option value=79 class="i3">Daruvar</option>  
<option value=94 class="i3">Garešnica</option>
<option value=329 class="i3">Grubišno Polje</option>
<option value=368 class="i3">Čazma</option>
<option value=6 class="i2">Brodsko-posavska županija</option>
<option value=342 class="i3">Gornji Bogićevci</option>
<option value=158 class="i3">Klakar</option>
<option value=140 class="i3">Nova Gradiška</option>
</select>
</form>

<script>
<!--
        window.onload = loadFilter;
// -->   
</script>

JavaScript:

function loadFilter() {
  'use strict';
  // indents all options depending on "i" CSS class
  function add_nbsp() {
    var opt = document.getElementsByTagName("option");
    for (var i = 0; i < opt.length; i++) {
      if (opt[i].className[0] === 'i') {
      opt[i].innerHTML = Array(3*opt[i].className[1]+1).join("&nbsp;") + opt[i].innerHTML;      // this means "&nbsp;" x (3*$indent)
      }
    }
  }
  // detects browser
  navigator.sayswho= (function() {
    var ua= navigator.userAgent, tem,
    M= ua.match(/(opera|chrome|safari|firefox|msie|trident(?=\/))\/?\s*([\d\.]+)/i) || [];
    if(/trident/i.test(M[1])){
        tem=  /\brv[ :]+(\d+(\.\d+)?)/g.exec(ua) || [];
        return 'IE '+(tem[1] || '');
    }
    M= M[2]? [M[1], M[2]]:[navigator.appName, navigator.appVersion, '-?'];
    if((tem= ua.match(/version\/([\.\d]+)/i))!= null) M[2]= tem[1];
    return M.join(' ');
  })();
  // quick detection if browser is firefox
  function isFirefox() {
    var ua= navigator.userAgent,
    M= ua.match(/firefox\//i);  
    return M;
  }
  // indented select options support for non-firefox browsers
  if (!isFirefox()) {
    add_nbsp();
  }
}  

Ответ 8

Мне действительно нравится Broken Arrow solution выше в этом сообщении. Я только немного улучшил/изменил его, так что так называемые метки можно переключать и не считаться опциями. Я использовал небольшой кусок jQuery, но это можно сделать без jQuery.

Я заменил промежуточные метки (без метки листа) ссылками, которые вызывают функцию при нажатии. Эта функция отвечает за переключение следующего div на ссылку с кликом, чтобы он расширял/сворачивал параметры. Это позволяет избежать выбора промежуточного элемента в иерархии, который обычно является чем-то желательным. Создание варианта, позволяющего выбирать промежуточные элементы, должно быть легким.

Это измененный html:

<div class="NestedSelect">
    <a onclick="toggleDiv(this)">Fruit</a>
    <div>
        <label>
            <input type="radio" name="MySelectInputName"><span>Apple</span></label>
        <label>
            <input type="radio" name="MySelectInputName"><span>Banana</span></label>
        <label>
            <input type="radio" name="MySelectInputName"><span>Orange</span></label>
    </div>

    <a onclick="toggleDiv(this)">Drink</a>
    <div>
        <label>
            <input type="radio" name="MySelectInputName"><span>Water</span></label>

        <a onclick="toggleDiv(this)">Soft</a>
        <div>
            <label>
                <input type="radio" name="MySelectInputName"><span>Cola</span></label>
            <label>
                <input type="radio" name="MySelectInputName"><span>Soda</span></label>
            <label>
                <input type="radio" name="MySelectInputName"><span>Lemonade</span></label>
        </div>

        <a onclick="toggleDiv(this)">Hard</a>
        <div>
            <label>
                <input type="radio" name="MySelectInputName"><span>Bear</span></label>
            <label>
                <input type="radio" name="MySelectInputName"><span>Whisky</span></label>
            <label>
                <input type="radio" name="MySelectInputName"><span>Vodka</span></label>
            <label>
                <input type="radio" name="MySelectInputName"><span>Gin</span></label>
        </div>
    </div>
</div>

Небольшая функция javascript/jQuery:

function toggleDiv(element) {
    $(element).next('div').toggle('medium');
}

И css:

.NestedSelect {
    display: inline-block;
    height: 100%;
    border: 1px Black solid;
    overflow-y: scroll;
}

.NestedSelect a:hover, .NestedSelect span:hover  {
    background-color: #0092ff;
    color: White;
    cursor: pointer;
}

.NestedSelect input[type="radio"] {
    display: none;
}

.NestedSelect input[type="radio"] + span {
    display: block;
    padding-left: 0px;
    padding-right: 5px;
}

.NestedSelect input[type="radio"]:checked + span {
    background-color: Black;
    color: White;
}

.NestedSelect div {
    display: none;
    margin-left: 15px;
    border-left: 1px black
    solid;
}

.NestedSelect label > span:before, .NestedSelect a:before{
    content: '- ';
}

.NestedSelect a {
    display: block;
}

Запуск образца в JSFiddle