J'ai créé un contrôle client DropDownList c qui peut rendre son contenu optgroups (pas à partir de zéro, j'ai édité du code trouvé sur Internet, bien que je comprenne exactement ce qu'il fait), et cela fonctionne bien.
Cependant, je suis maintenant confronté à une situation où il me faut deux niveaux d’indentation dans ma liste déroulante, c’est-à-dire.
<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>
Cependant, dans l'exemple ci-dessus, il est rendu comme si Level Two
était au même niveau d'indentation que Level One
.
Existe-t-il un moyen de produire le comportement optgroup imbriqué que je recherche?
Ok, si quelqu'un lit jamais ceci: la meilleure option est d’ajouter quatre
À chaque niveau supplémentaire d’indentation, cela semblerait!
alors:
<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>
La spécification HTML ici est vraiment cassée. Il devrait autoriser les groupes optionnels imbriqués et recommander aux agents utilisateurs de les rendre sous forme de menus imbriqués. À la place, n seul niveau optgroup est autorisé . Cependant, ils doivent dire ce qui suit:
Remarque. Les développeurs sont informés que les futures versions de HTML pourraient étendre le mécanisme de regroupement pour autoriser les groupes imbriqués (c.-à-d. Que des éléments OPTGROUP pourraient être imbriqués). Cela permettra aux auteurs de représenter une hiérarchie de choix plus riche.
Et les agents utilisateurs pourraient commencer à utiliser les sous-menus pour rendre les groupes d’options au lieu d’afficher les titres avant le premier élément d’option d’un groupe opt, comme ils le font maintenant.
C'est très bien, mais si vous ajoutez une option qui n'est pas dans optgroup, cela devient un buggy.
<select>
<optgroup label="Level One">
<option> A.1 </option>
<optgroup label=" Level Two">
<option> A.B.1 </option>
</optgroup>
<option> A.2 </option>
</optgroup>
<option> A </option>
</select>
Ce serait bien mieux si vous utilisiez css et fermiez optgroup tout de suite:
<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>
<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>
J'aime beaucoup le solution de Broken Arrow ci-dessus dans ce post. Je viens juste de l’améliorer/de le changer un peu pour que ce que l’on appelle les étiquettes puisse être basculé et ne soit pas considéré comme une option. J'ai utilisé un petit morceau de jQuery, mais cela pourrait se faire sans jQuery.
J'ai remplacé les étiquettes intermédiaires (pas d'étiquettes de feuille) par des liens qui appellent une fonction au clic. Cette fonction est chargée de basculer la prochaine division du lien cliqué, afin d’agrandir/réduire les options. Cela évite la possibilité de sélectionner un élément intermédiaire dans la hiérarchie, ce qui est généralement souhaité. Faire une variante qui permet de sélectionner des éléments intermédiaires devrait être facile.
Voici le code HTML modifié:
<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>
Une petite fonction javascript/jQuery:
function toggleDiv(element) {
$(element).next('div').toggle('medium');
}
Et le 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;
}
Je pense que si vous avez quelque chose d'aussi structuré et complexe, vous pourriez envisager autre chose qu'un menu déroulant unique.
J'avais besoin d'une solution propre et légère (donc pas de jQuery ou similaire), qui ressemblera exactement à du HTML simple, continuerait également à fonctionner lorsque seul le HTML simple est prédéfini (javascript sera donc amélioré), et qui permettra de chercher en commençant par des lettres ( y compris les lettres UTF-8 nationales) si possible sans alourdissement supplémentaire. Il doit également fonctionner rapidement sur les navigateurs très lents (pensez à rPi - de manière à ce qu'aucun javascript ne soit exécuté après le chargement de la page).
Dans Firefox, il utilise l’identification CSS et permet donc la recherche par lettres. Dans d’autres navigateurs, il utilisera
preending (mais la recherche rapide par lettres n’est pas prise en charge). En tout cas, je suis assez content des résultats.
Vous pouvez essayez en action ici
Ça va comme ça:
CSS:
.i0 { }
.i1 { margin-left: 1em; }
.i2 { margin-left: 2em; }
.i3 { margin-left: 3em; }
.i4 { margin-left: 4em; }
.i5 { margin-left: 5em; }
HTML (classe "i1", "i2" etc désignent le niveau d'identification):
<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(" ") + opt[i].innerHTML; // this means " " 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();
}
}
Je sais que c'était il y a longtemps, mais j'ai un petit supplément à ajouter:
Ce n'est pas possible dans HTML5 ou dans les spécifications précédentes, ni proposé dans HTML5.1 pour le moment. J'ai fait une demande au public-html-comments
liste de diffusion, mais nous verrons s’il en résulte quelque chose.
Quoi qu’il en soit, bien que cela ne soit pas possible avec <select>
et pourtant, vous pouvez obtenir un effet similaire avec le code HTML suivant, plus quelques CSS pour la beauté:
<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>
Cela signifie également que vous pouvez autoriser la sélection du <optgroups>
_ eux-mêmes. Cela peut être utile si vous avez, par exemple, des catégories imbriquées dans lesquelles les catégories sont très détaillées et que vous souhaitez permettre aux utilisateurs de sélectionner plus haut dans la hiérarchie.
Tout cela fonctionnera sans JavaScript, mais vous pouvez en ajouter pour masquer les boutons radio, puis changer la couleur de fond de l'élément sélectionné ou de quelque chose.
N'oubliez pas que cette solution est loin d'être parfaite, mais si vous avez absolument besoin d'une sélection imbriquée offrant une compatibilité raisonnable entre navigateurs, cette solution est probablement aussi proche que possible.