Input multiple with tags without autoCompletion

2019-02-20 18:54发布

问题:

I have two inputs.

I want the two inputs to have the same look and feel see below:

The first input use autocomplete and allows the user to select a list of terms => I use p:autocomplete (see Primefaces documentation on autocomplete) This input works fine.

For the second input, I would like to have the same display but without any autocompletion : the user just enter a list of terms with no autocompletion at all. I tried to have a fake autocomplete that return the value given by the user but it is too slow and the behaviour is not correct when the user quit the input.

Any idea is welcome.

回答1:

After a quick look at the PrimeFaces javascript code of the autoComplete and a few hours experimenting with it, I came up with a solution. It involves overriding the bindKeyEvents and in it deciding to call the original one or not, adding detection for the space key ('selecting a tag') and when pressed, add the tag and fire the selectionEvent (if ajax is used). Place the following code in your page or in an external javascript file

   <script>
   //<![CDATA[

            if(PrimeFaces.widget.AutoComplete) {

                PrimeFaces.widget.AutoComplete = PrimeFaces.widget.AutoComplete.extend ( {

                    bindKeyEvents: function() {
                        if (this.input.attr('data-justTags')) { 

                            var $this = this;

                            this.input.on('keyup.autoComplete', function(e) {
                                var keyCode = $.ui.keyCode,
                                key = e.which;

                            }).on('keydown.autoComplete', function(e) {
                                var keyCode = $.ui.keyCode;

                                $this.suppressInput = false;
                                switch(e.which) {

                                    case keyCode.BACKSPACE:
                                        if ($this.cfg.multiple && !$this.input.val().length) {
                                            $this.removeItem(e, $(this).parent().prev());

                                            e.preventDefault();
                                        }
                                    break;

                                    case keyCode.SPACE:

                                        if($this.cfg.multiple) {
                                            var itemValue = $this.input.val();

                                            var itemDisplayMarkup = '<li data-token-value="' +itemValue + '"class="ui-autocomplete-token ui-state-active ui-corner-all ui-helper-hidden">';
                                            itemDisplayMarkup += '<span class="ui-autocomplete-token-icon ui-icon ui-icon-close" />';
                                            itemDisplayMarkup += '<span class="ui-autocomplete-token-label">' + itemValue + '</span></li>';

                                            $this.inputContainer.before(itemDisplayMarkup);
                                            $this.multiItemContainer.children('.ui-helper-hidden').fadeIn();
                                            $this.input.val('').focus();

                                            $this.hinput.append('<option value="' + itemValue + '" selected="selected"></option>');
                                            if($this.multiItemContainer.children('li.ui-autocomplete-token').length >= $this.cfg.selectLimit) {
                                                $this.input.css('display', 'none').blur();
                                                $this.disableDropdown();
                                            }

                                            $this.invokeItemSelectBehavior(e, itemValue);    
                                         }


                                    break;
                                };

                            });
                     } else {
                         //console.log("Original bindEvents");
                         this._super();
                     }
                }
            });
        }


   //]]>

    </script>

For deciding on when to call the original one or not, I decided to use a passThrough attribute with a data-justTags name. e.g. pt:data-justTags="true" (value does not matter, so pt:data-justTags="false" is identical to pt:data-justTags="true"). A small html snippet of this is:

<p:autoComplete pt:data-justTags="true" multiple="true" value="#{myBean.selectedValues}">

And do not forget to add the xmlns:pt="http://xmlns.jcp.org/jsf/passthrough" namespace declaration.



回答2:

I found a component that could do the job : http://www.butterfaces.org/tags.jsf