remote autocomplete by typeahead works only on uni

2020-08-01 12:32发布

问题:

I am having problem setting up typeahead with bloodhound on two fields - symbol and name. You can try live version on my DGI portfolio manager and autocomplete remote source here.
Typeahead sometimes works and sometimes it does not.
If I type symbols like "jnj", "mcd", "aapl" it works.
However, when I type string from name like "corporation" and "inc" that have around 3000 objects with this name, it does not work. I doubt it is because it is loading, since json file is served quickly(under 250ms on localhost).
Firstly, I thought symbols work correctly and names are ignored. But I do get proper typeahead for some names: "apple" and "homestreet" for instance.
I believe it only works if there are 1 or 2 results. But I don't understand, json file serves always max 5 results.
Here are my codes:
views.py for autocomplete url:

from haystack.query import SearchQuerySet
import json
def autocomplete(request):
    if request.GET.get('q', '') == '':
        array = []
    else:
        sqs = SearchQuerySet().models(Stock)
        sqs_symbol = sqs.filter(symbol_auto=request.GET.get('q', ''))
        sqs_name = sqs.filter(name_auto=request.GET.get('q', ''))
        sqs_result = sqs_symbol | sqs_name
        array = []
        print sqs_result.count()
        for result in sqs_result[:5]:
            data = {"symbol": str(result.symbol),
                     "name": str(result.name),
                     "tokens": str(result.name).split()
                    }
            array.insert(0, data)
        print array
    return HttpResponse(json.dumps(array), content_type='application/json')

I added print so I know when it does not work. search_indexes.py file:

from haystack import indexes
from stocks.models import Stock

class StockIndex(indexes.SearchIndex, indexes.Indexable):
    text = indexes.CharField(document=True, use_template=True)
    symbol = indexes.CharField(model_attr='symbol')
    name = indexes.CharField(model_attr='name')

    # We add this for autocomplete.
    symbol_auto = indexes.EdgeNgramField(model_attr='symbol')
    name_auto = indexes.EdgeNgramField(model_attr='name')

    def get_model(self):
        return Stock

    def index_queryset(self, using=None):
        """Used when the entire index for model is updated."""
        return self.get_model().objects.all()

And in my template html file:

<script type="text/javascript">
    $(function(){
        var stocks = new Bloodhound({
            datumTokenizer: function (datum) {
                return Bloodhound.tokenizers.whitespace(datum.tokens);
            },
            queryTokenizer: Bloodhound.tokenizers.whitespace,
            limit: 5,
            remote: {
                url: "/search/autocomplete/",
                replace: function(url, query) {
                    return url + "?q=" + query;
                },
                filter: function(stocks) {
                    return $.map(stocks, function(data) {
                        return {
                            tokens: data.tokens,
                            symbol: data.symbol,
                            name: data.name
                        }
                    });
                }
            }
        });
        stocks.initialize();
        $('.typeahead').typeahead(null, {
                name: 'stocks',
                displayKey: 'name',
                minLength: 1, // send AJAX request only after user type in at least X characters
                source: stocks.ttAdapter(),
                templates: {
                    suggestion: function(data){
                      return '<p>' + data.name + ' (<strong>' + data.symbol + '</strong>)</p>';
                    }
                }
        }).on('typeahead:selected', function (obj, stock) {
            window.location.href = "/stocks/detail/" + stock.symbol;
        });
    });
</script>

EDIT: Some Examples

Json response:

[{"tokens": ["Johnson", "&", "Johnson"], "symbol": "JNJ", "name": "Johnson & Johnson"}]

Not working for "sto":

json response:

[{"tokens": ["QKL", "Stores,", "Inc."], "symbol": "QKLS", "name": "QKL Stores, Inc."}, {"tokens": ["SPDR", "DJ", "STOXX", "50"], "symbol": "FEU", "name": "SPDR DJ STOXX 50 "}, {"tokens": ["Statoil", "ASA"], "symbol": "STO", "name": "Statoil ASA"}, {"tokens": ["STORE", "Capital", "Corporation"], "symbol": "STOR", "name": "STORE Capital Corporation"}, {"tokens": ["StoneMor", "Partners", "L.P."], "symbol": "STON", "name": "StoneMor Partners L.P."}]

回答1:

It is typeahead.js's bug. It should be fixed in version 0.11.2.