如何在自动完成中建议相似词

How to suggest similar words in autocomplete

我有一个带有 jquery-ui- 自动完成功能的位置输入字段。

<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>

但是,我对同一位置可以有不同名称的情况不满意。

例如,假设用户想要查找 Mallorca。他可以写:MallorcaMajorcaPalma de MallorcaPMI帕尔马.

我的第一个想法是使用 label 属性

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

但是,这可能会让人非常困惑。写入 Ma 自动完成将显示 MallorcaPalma de MallorcaMajorca,即使他们在同一个地方。

我希望用户在键入 Ma 时只会得到一个建议。同样,无论用户输入 MajMal 还是 Pal,他都应该只得到一个马略卡岛的建议术语。

理想情况下,一个名为 input 的附加 属性 作为要搜索的输入关键字将是完美的。然后,拥有一个属性为 valueinput 的数组就可以了。不幸的是,我没有在文档中找到这样的东西。

如您所见,我使用 array 作为源类型。对于我读到的内容,也许 function 类型可以让我做这样的事情,但我不清楚如何做,因为我对 js 不是很熟悉,也没有找到任何明确的例子。

我怎样才能以简单的方式实现它?

你快到了。您可以使用 response 函数 (see in API) 从结果中删除备选拼写。还要将最佳拼写(在本例中为 "Mallorca")放在最后。看看这个,我希望这些评论足以让你明白逻辑。尝试键入 "Ma" 或 "Maj" 和 select 唯一的选项。在这两种情况下,它都会显示 "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>

经过一些额外的研究和多次尝试,我找到了一种方法。这是 Django 特有的,因此当然欢迎任何其他更通用的建议。

该解决方案基于 this tutorial,但进行了一些修改。


首先,在模板中导入jQuery和jQueryUI:

<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>

之后,在模板本身中,您需要为输入标签分配一个 id。请注意,此 ID 是 jquery 将如何识别 运行 自动完成的形式。

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

javascript代码如下:

<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>

并且urls.py文件需要做相应的修改:

# urls.py

import yourapp.views

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

最后创建 django 视图。函数名必须和urls.py中写的和javascript中source中写的一样。

#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)

并且自动完成应该可以工作。