web-dev-qa-db-fra.com

Twitter bootstrap typeahead plusieurs valeurs?

J'utilise Twitter Bootstrap avec Jquery ..__ Je veux utiliser la fonction TYPEAHEAD pour une zone de texte qui m'a permis de travailler très facilement .sélection multiple.

Je veux dire par là, après avoir sélectionné un mot de la saisie semi-automatique, il me ramène à textarea avec un espace supplémentaire après, puis si je recommence à taper, il me propose de le refaire.

Voici un JS bin: http://jsbin.com/ewubuk/1/edit (Rien de spécial à l'intérieur).

Existe-t-il une solution simple permettant la sélection multiple avec une tête de saisie? Si oui comment?

Merci d'avance.

44
denislexic

Edit Il y avait déjà une attraction à ce sujet: https://github.com/Twitter/bootstrap/pull/2007


Vous pouvez aborder le comportement souhaité en utilisant un proxy pour le caractère: Demo (jsfiddle)

var $myTextarea = $('#myTextarea');

$('.typeahead').typeahead({
    source: source,
    updater: function(item) {
        $myTextarea.append(item, ' ');
        return '';
    }
});

Je pense que la méthode updater est destinée à ce genre de chose, vous retournez juste ce qui sera affiché.


Ou si vous voulez vraiment que tout se trouve dans le même élément input, vous devez remplacer plus de méthodes afin qu'il ne corresponde qu'à l'élément actuellement typé: Demo (jsfiddle)

function extractor(query) {
    var result = /([^,]+)$/.exec(query);
    if(result && result[1])
        return result[1].trim();
    return '';
}

$('.typeahead').typeahead({
    source: source,
    updater: function(item) {
        return this.$element.val().replace(/[^,]*$/,'')+item+',';
    },
    matcher: function (item) {
      var tquery = extractor(this.query);
      if(!tquery) return false;
      return ~item.toLowerCase().indexOf(tquery.toLowerCase())
    },
    highlighter: function (item) {
      var query = extractor(this.query).replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&')
      return item.replace(new RegExp('(' + query + ')', 'ig'), function ($1, match) {
        return '<strong>' + match + '</strong>'
      })
    }
});

Celui-ci n'est pas idiot, car vous devez taper à la fin, après le caractère spécial.

88
Sherbrow

C'est un excellent remplacement pour certaines boîtes:

http://ivaynberg.github.io/select2/

(Si vous utilisez la version à plusieurs valeurs.)

12
James Head

La réponse la plus fréquente ne semble plus fonctionner avec le dernier typeahead , je vous propose donc ce qui suit.

VIOLON

function MultiTypeahead(id, data, trigger, vertAdjustMenu)
{
    trigger = (undefined !== trigger) ? trigger : '';
    var validChars = /^[a-zA-Z]+$/;


    function extractor(query)
    {
        var result = (new RegExp('([^,; \r\n]+)$')).exec(query);
        if(result && result[1])
            return result[1].trim();
        return '';
    }

    var lastUpper = false;
    function strMatcher(id, strs) 
    {
        return function findMatches(q, sync, async) 
        {
            var pos = $(id).caret('pos');
            q = (0 < pos) ? extractor(q.substring(0, pos)) : '';

            if (q.length <= trigger.length)
                return;

            if (trigger.length)
            {
                if(trigger != q.substr(0, trigger.length))
                    return;

                q = q.substr(trigger.length);
            }

            if (!q.match(validChars))
                return;

            var firstChar = q.substr(0, 1);
            lastUpper = (firstChar === firstChar.toUpperCase() && firstChar !== firstChar.toLowerCase());

            var cpos = $(id).caret('position');
            $(id).parent().find('.tt-menu').css('left', cpos.left + 'px');
            if (vertAdjustMenu)
                $(id).parent().find('.tt-menu').css('top', (cpos.top + cpos.height) + 'px');

            var matches = [];
            var matches = [], substrRegex = new RegExp(q, 'i');
            $.each(strs, function(i, str) 
            {
                if (str.length > q.length && substrRegex.test(str))
                    matches.Push(str);
            });

            if (!matches.length)
                return;

            sync(matches);
        };
    };

    var lastVal = '';
    var lastPos = 0;
    function beforeReplace(event, data)
    {
        lastVal = $(id).val();
        lastPos = $(id).caret('pos');
        return true;
    }

    function onReplace(event, data)
    {            
        if (!data || !data.length)
            return;

        if (!lastVal.length)
            return;

        var root = lastVal.substr(0, lastPos);
        var post = lastVal.substr(lastPos);

        var typed = extractor(root);
        if (!lastUpper && typed.length >= root.length && 0 >= post.length)
            return;

        var str = root.substr(0, root.length - typed.length);

        str += lastUpper ? (data.substr(0, 1).toUpperCase() + data.substr(1)) : data;
        var cursorPos = str.length;

        str += post;

        $(id).val(str);
        $(id).caret('pos', cursorPos);      
    }

    this.typeahead = 
        $(id).typeahead({hint: false, highlight: false}, {'limit': 5, 'source': strMatcher(id, data)})
                .on('typeahead:beforeselect', beforeReplace)
                .on('typeahead:beforeautocomplete', beforeReplace)
                .on('typeahead:beforecursorchange', beforeReplace)
                .on('typeahead:selected', function(event,data){setTimeout(function(){ onReplace(event, data); }, 0);})
                .on('typeahead:autocompleted', onReplace)
                .on('typeahead:cursorchange', onReplace)
                ;
}

EDIT: Réalisant que le code précédent contenait trop de choses supplémentaires, je l'ai réduit à un exemple de travail minimal. 

This est ce qui était précédemment posté ..

3
bob2

J'imagine que vous pouvez éditer le plug-in pour permettre plusieurs sélections (ne fermez pas le menu déroulant) et ajouter les valeurs sélectionnées en les séparant par une virgule. Le seul problème que je vois est que vous ne savez pas quand fermer la liste déroulante.

1
superlukas

Je suis en retard pour la fête, mais c'est ce que j'ai proposé pour Bootstrap v4. Il nécessite également d3 (car jQuery n’est pas aussi familier). 

Vous pouvez voir un exemple fonctionnant à http://sumneuron.gitlab.io/multitags/ enter image description here

Il a quelques fonctionnalités utiles, est écrit de manière claire, et devrait donner un bon départ à ceux qui le trouvent. Surtout si vous avez déjà été curieux de savoir comment le marquage est implémenté. 

 enter image description here

Le code est disponible sur https://gitlab.com/SumNeuron/multitags/pipelines

La logique est à peu près la suivante:

if keydown in [enter, ","]:
    // logic of function "doneTyping" 
    text = parse(text) // get text from textarea and grab latest value
    if text is valid:
        renderTag(text) // put the text in a tag element
        updateHiddenForm(text) // update the hidden form to include the tag
    else:
        notifyUserOfInvalidTag(text) // alert user
else:
    // logic of function "stillTyping" 
    suggest = bloodhoundSearch(text) // use Twitter typeahead
    updateSuggestionBox(suggest) // display results from typeahead
0
SumNeuron