web-dev-qa-db-fra.com

Comment éviter le ctrl-clic dans une boîte multi-sélection en utilisant Javascript?

Je pensais que ce serait un simple bidouillage, mais je cherche depuis des heures et je ne vois pas comment trouver le bon terme. Je veux avoir une boîte de sélection multiple normale (<select multiple="multiple">), sauf que je ne veux pas que l'utilisateur ait à maintenir la touche Ctrl enfoncée pour effectuer plusieurs sélections. 

En d'autres termes, je veux un clic gauche pour faire basculer l'élément <option> qui se trouve sous le curseur sans changer aucun des autres. En d'autres termes, je veux quelque chose qui ressemble à une liste déroulante mais se comporte comme un groupe de cases à cocher.

Quelqu'un peut-il suggérer un moyen simple de le faire en Javascript? Merci.

54
bokov

Vérifiez ce violon: http://jsfiddle.net/xQqbR/1022/

En gros, vous devez remplacer l'événement mousedown pour chaque <option> et y activer la propriété selected.

$('option').mousedown(function(e) {
    e.preventDefault();
    $(this).prop('selected', !$(this).prop('selected'));
    return false;
});

Pour plus de simplicité, j'ai choisi l'option 'comme sélecteur ci-dessus. Vous pouvez l’ajuster pour correspondre à <option>s sous un ou plusieurs éléments <select> spécifiques. Par exemple: $('#mymultiselect option')

90
techfoobar

Dû résoudre ce problème moi-même et j'ai remarqué le comportement buggé une simple interception de la mousedown et la définition de l'attribut aurait, donc fait une substitution de l'élément select et cela fonctionne bien.

jsFiddle: http://jsfiddle.net/51p7ocLw/

Remarque: Ce code corrige le comportement problématique en remplaçant l'élément select dans le DOM. Ceci est un peu agressif et va casser les gestionnaires d’événements que vous pourriez avoir attachés à l’élément.

window.onmousedown = function (e) {
    var el = e.target;
    if (el.tagName.toLowerCase() == 'option' && el.parentNode.hasAttribute('multiple')) {
        e.preventDefault();

        // toggle selection
        if (el.hasAttribute('selected')) el.removeAttribute('selected');
        else el.setAttribute('selected', '');

        // hack to correct buggy behavior
        var select = el.parentNode.cloneNode(true);
        el.parentNode.parentNode.replaceChild(select, el.parentNode);
    }
}
<h4>From</h4>

<div>
    <select name="sites-list" size="7" multiple>
        <option value="site-1">SITE</option>
        <option value="site-2" selected>SITE</option>
        <option value="site-3">SITE</option>
        <option value="site-4">SITE</option>
        <option value="site-5">SITE</option>
        <option value="site-6" selected>SITE</option>
        <option value="site-7">SITE</option>
        <option value="site-8">SITE</option>
        <option value="site-9">SITE</option>
    </select>
</div>

18
Sergio

la réponse de techfoobar est boguée, elle désélectionne toutes les options si vous faites glisser la souris.

La réponse de Sergio est intéressante, mais cloner et supprimer des événements liés à une liste déroulante n’est pas une bonne chose.

Essayez cette réponse .

Remarque: ne fonctionne pas sur Firefox, mais parfaitement sur Safari/Chrome/Opera. (Je ne l'ai pas testé sur IE)

5
evilReiko

Nécromancie. 
La réponse sélectionnée sans jQuery. 
En outre, il a manqué de définir le focus lorsque l’on clique sur une option, car vous devez le faire vous-même si vous écrivez e.preventDefault 
Oublier de faire le focus aurait une incidence sur le style CSS, par exemple. bootstrap, etc.

var options = [].slice.call(document.querySelectorAll("option"));

options.forEach(function (element)
{
    // console.log("element", element);
    element.addEventListener("mousedown", 
        function (e)
        {
            e.preventDefault();
            element.parentElement.focus();
            this.selected = !this.selected;
            return false;
        }
        , false
    );
});
0
Stefan Steiger

J'ai eu le même problème aujourd'hui, généralement le conseil est d'utiliser une liste de cases à cocher cachées et d'émuler le comportement via css, de cette façon, il est plus facile à gérer, mais dans mon cas, je ne veux pas modifier le langage HTML.

Pour le moment, je n'ai testé ce code qu'avec Google Chrome. Je ne sais pas s'il fonctionne avec un autre navigateur, mais il devrait:

var changed;
$('select[multiple="multiple"]').change(function(e) {
    var select = $(this);
    var list = select.data('prevstate');
    var val = select.val();
    if (list == null) {
        list = val;
    } else if (val.length == 1) {
        val = val.pop();
        var pos = list.indexOf(val);
        if (pos == -1)
            list.Push(val);
        else
            list.splice(pos, 1);
    } else {
        list = val;
    }
    select.val(list);
    select.data('prevstate', list);
    changed = true;
}).find('option').click(function() {
    if (!changed){
        $(this).parent().change();
    }
    changed = false;
});

Bien sûr, les suggestions sont les bienvenues mais je n'ai pas trouvé d'autre moyen

0