Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AngularJS: Order search results by similarity to search text

I have built countless angular-powered, find-as-you-type-style searches over the past year or so, and I love how easy they are to implement. However, one problem I've never found a good solution for is how to properly sort those search results. I would really appreciate anyone who has ideas on how to do this.

Here's my problem:

Please see This Plunker for reference

If you look at this super-simple example plunker above, I have a list of sample pets that I want to be able to search through. If I type any text into the field, the list of pets gets narrowed down. This is all great. My problem, is that the search results aren't sorted in relation to how similar they are to the text that was entered.

For example:

There are a total of 8 pets in the list, sorted by name using the orderBy:'name' filter on the list's ng-repeat directive. If I type just the character T into the input, I get only 5 remaining results. But the pet at the top of the list is "blackie" (because blackie is the first pet in the list that has a t in it, because blackie's type is "cat", which contains a t).

Sample search results

What I would like to see is a way to sort the remaining results by their similarity to the search text. So, in the example above, instead of seeing "blackie" at the top of the list, I would see "tom" (which is at the bottom of the filtered list) because tom's name actually starts with the letter t, which is what I started searching for and is more likely to be what I am trying to find.

Any ideas on how to implement this sort of search algorithm? I haven't been able to find anything in all of my googling and all of my attempts to write such an algorithm.

Thanks in advance for the ideas!

like image 590
tennisgent Avatar asked Nov 25 '25 15:11

tennisgent


1 Answers

Define your own filter to narrow down the list and for each item calculate a rank and assign the calculated rank to that item. Then order by rank.

Change HTML like this:

<pre ng-repeat="pet in pets | ranked:inputText | orderBy:'rank':true">{{pet | json}}</pre>

Add the following filter:

app.filter('ranked', function() {
return function(obj, searchKey)
{
  if (!obj)
    return obj;
  for(var i =0; i< obj.length; i++)
  {
     var currentObj = obj[i];
      var numOfName = currentObj.name.indexOf(searchKey) + 1;
      var numOfType = currentObj.type.indexOf(searchKey) + 1;
      var numOfColor = currentObj.color.indexOf(searchKey) + 1;

      currentObj.rank = numOfName * 10 + numOfType * 5 + numOfColor;
  }
  return obj;
}
});
like image 146
Aidin Avatar answered Nov 27 '25 04:11

Aidin



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!