How to suggest similar words in autocomplete

大憨熊 提交于 2019-11-29 23:35:40

问题


I have an input field for locations with jquery-ui-autocomplete.

<script type="text/javascript">
    $(document).ready(function(){
        var location_input=$('input[id="location-autocomplete"]');
        var cityNames = [
            { value: 'Mallorca' },
            { value: 'Berlin' },
            { value: 'London' },
            // many other elements
        ];
        location_input.autocomplete({
          source: cityNames,
          minLength: 2
        });
      } );

    //   keeps same width as box
      jQuery.ui.autocomplete.prototype._resizeMenu = function () {
          var ul = this.menu.element;
          ul.outerWidth(this.element.outerWidth());
        }
</script>

However, I am not happy with the case when the same location can have different names.

For example, let's say that the user wants to look for Mallorca. He could write: Mallorca, Majorca, Palma de Mallorca, PMI or Palma.

My first idea was to use the label property

var cityNames = [
    { value: 'Mallorca', label: 'Palma de Mallorca' },
    { value: 'Mallorca', label: 'Mallorca' },
    { value: 'Mallorca', label: 'Majorca' },
    // etc
    ];

However, this can be very confusing. Writing Ma the autocomplete would show Mallorca, Palma de Mallorca and Majorca, even if they are the same place.

I would like that when typing Ma the user only gets one suggestion. Similarly, no matter if the user types Maj, Mal or Pal, he should just get only one suggestion term for Mallorca.

Ideally, an additional property called input working as the input keyword to be searched would have been perfect. Then, having an array with the properties value and input for each would have done the trick. Unfortunately, I did not find such a thing in the docs.

As you can see, I am using as source type an array. For what I read, maybe the function type would allow me to do something like this, but it is not clear to me how, as I am not very familiar with js and did not find any clear example about it.

How could I achieve that in a simple way?


回答1:


You are almost there. You can use the response function (see in API) to remove the alternate spellings from the results. Also put the best spelling ("Mallorca" in this case) last. Check this out, I hope the comments are enough to get the logic. Try to type "Ma", or "Maj" and select the only option. In both cases it will display "Mallorca"

 $( function() {
    var availableTags = [      
    { value: 'Mallorca', label: 'Palma de Mallorca' },
    { value: 'Mallorca', label: 'Majorca' },
    { value: 'Mallorca', label: 'Mallorca' },
    { value: 'Madrid', label: 'Madrid' }
    ];
    $( "#tags" ).autocomplete({
      source: availableTags,      
      response: function( event, ui ) {
        var added = [];//Keep here the unique labels that are already in the list
        for(var i=ui.content.length-1;i>=0;i--){//Start a loop, itterate all items backwards
          var cur = ui.content[i].value;//Value of the item
          if($.inArray(cur,added)==-1){//If not already loaded
            added.push(cur);//Put the new item in the list
          }else{            
            ui.content.splice(i,1);//If already loaded remove it from the results
          }
        }        
      }
    });
  } );
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
<div class="ui-widget">
  <label for="tags">Tags: </label>
  <input id="tags">
</div>



回答2:


After some additional research and many tries, I found a way to do it. This is specific for Django, so any other more generic proposal is of course more than welcome.

The solution is based on this tutorial, although with some modifications.


First of all, import jQuery and jQueryUI in the template:

<link rel="stylesheet" href="http://code.jquery.com/ui/1.8.18/themes/base/jquery-ui.css" type="text/css" media="all" />
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js" type="text/javascript"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.16/jquery-ui.min.js" type="text/javascript"></script>

Afterwards, in the template itself, you need to assign an id to the input tag. Note that this id is how jquery will identify in which form to run the autocomplete.

<div class="ui-widget">
  <label for="cities">City: </label>
  <input id="autocomplete-cities">
</div>

The javascript code is as follows:

<script type="text/javascript">
    $(document).ready(function(){
        var location_input=$('input[id="autocomplete-city"]');
        location_input.autocomplete({
          source: "/api/get_city_names/",
          minLength: 2
        });
      } );

    //   keeps same width as box
      jQuery.ui.autocomplete.prototype._resizeMenu = function () {
          var ul = this.menu.element;
          ul.outerWidth(this.element.outerWidth());
        }
</script>

And urls.py file needs to be modified accordingly:

# urls.py

import yourapp.views

urlpatterns = [
    ...,
    url(r'^api/get_city_names/', yourapp.views.get_city_names),
    ...,
]

And finally create the django view. The name of the function has to be the same as the one written in urls.py and the one written in the source of the javascript.

#views.py

import json

def get_city_names(request):

    #what was in the question an array is now a python list of dicts.
    #it can also be in some other file and just imported.
    all_city_names = [
    { good_name: 'Mallorca', input_name: 'Palma de Mallorca' },
    { good_name: 'Mallorca', input_name: 'Mallorca' },
    { good_name: 'Mallorca', input_name: 'Majorca' },
    # etc
    ]

    if request.is_ajax():
        q = request.GET.get('term', '')

        city_names = [c['good_name'] for c in all_city_names if q in c["input_name"]]
        city_names = set(city_names) #removing duplicates

        results = []
        for cn in city_names:
            cn_json = {'value': cn}
            results.append(cn_json)
        data = json.dumps(results)
    else:
        data = 'fail'
    mimetype = 'application/json'
    return HttpResponse(data, mimetype)

And the autocomplete should work.



来源:https://stackoverflow.com/questions/42224605/how-to-suggest-similar-words-in-autocomplete

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!