Bloodhound identify bug?

1.6k views Asked by At

I'm using latest version of typeahead.js (v0.11.1). I observed strange behaviors when using different ids for dataset values.

I've created a JSFiddle. Here's the js code:

var ds = new Bloodhound({
    datumTokenizer: Bloodhound.tokenizers.obj.whitespace('name'),
    queryTokenizer: Bloodhound.tokenizers.whitespace,
    local: [{id: 1, name: "a b 1"}, {id: 2, name: "a b 2"}, {id: 3, name: "a"}],
    identify: function(obj) { return obj.id; }
});

$('#go').typeahead(null, {
    name: 'ds',
    display: 'name',
    source: ds
});

Now typeahead may malfunction if I change the data for 'local'. Here are just some examples:

Using one of these values for 'local' (notice the third element are random numbers starting with '1'):

[{id: 1, name: "a b 1"}, {id: 2, name: "a b 2"}, {id: 15, name: "a"}]

[{id: 1, name: "a b 1"}, {id: 2, name: "a b 2"}, {id: 1849, name: "a"}]

Now when I enter into text box: "a b", typeahead is expected to suggest "a b 1" and "a b 2", but in fact it only suggests "a b 1".

This can be fixed by one of these:

  • Change 'id' property of third element to a value that doesn't start with '1'. Example:

    [{id: 1, name: "a b 1"}, {id: 2, name: "a b 2"}, {id: 23, name: "a"}]

  • Change 'name' property of third element to a value that doesn't start with 'a'. Example:

    [{id: 1, name: "a b 1"}, {id: 2, name: "a b 2"}, {id: 15, name: "s"}]

  • Remove 'identify' property of Bloodhound constructor object.

What's more, if I use a number greater than 2 as id of first element, like this:

[{id: 3, name: "a b 1"}, {id: 2, name: "a b 2"}, {id: 15, name: "a"}]

Now when I enter "a b" into text box, there's no suggestion!

1

There are 1 answers

1
Tacaza On BEST ANSWER

Answering my own question. Yes there is a bug in bloodhound. SearchIndex.getIntersection() function is incorrectly implemented. You can take out this function and test it like this:

getIntersection([1,2,15],[1,2])

It is supposed to return [1,2] as result, but in fact it returns [1]. This is because it uses sort() function incorrectly to sort numbers. According to w3schools:

By default, the sort() method sorts the values as strings in alphabetical and ascending order.

This works well for strings ("Apple" comes before "Banana"). However, if numbers are sorted as strings, "25" is bigger than "100", because "2" is bigger than "1".

So this function can be fixed by changing these two lines:

        arrayA = arrayA.sort();
        arrayB = arrayB.sort();

into:

        arrayA = arrayA.sort(function(a, b){return a-b});
        arrayB = arrayB.sort(function(a, b){return a-b});

Took me 1 day to find out :(