angularjs search and ignore spanish characters - angularjs

I'm adding a simple sort on a page. The idea is to search products. These products are written in spanish language and has accents. For example: 'Jamón'.
Here is my code:
<div class="form-inline">
<label>Search</label>
<input type="text" ng-model="q"/>
</div>
<div ng-repeat="product in products_filtered = (category.products | filter:q | orderBy:'name')">
....
</div>
The only problem i have is that you have to type in "Jamón" in order to find the product "Jamón". What I want is to be more flexible, if the user types in "Jamon", the results must include "Jamón".
How can i search with angular filters and forget about accents? Any Idea?
Thanks in advance.

You'll need to create a filter function (or a full filter). This is the simplest thing that could possibly work:
HTML
<div ng-app ng-controller="Ctrl">
<input type="text" ng-model="search">
<ul>
<li ng-repeat="name in names | filter:ignoreAccents">{{ name }}</li>
</ul>
</div>
Javascript
function Ctrl($scope) {
function removeAccents(value) {
return value
.replace(/á/g, 'a')
.replace(/é/g, 'e')
.replace(/í/g, 'i')
.replace(/ó/g, 'o')
.replace(/ú/g, 'u');
}
$scope.ignoreAccents = function(item) {
if (!$scope.search) return true;
var text = removeAccents(item.toLowerCase())
var search = removeAccents($scope.search.toLowerCase());
return text.indexOf(search) > -1;
};
$scope.names = ['Jamón', 'Andrés', 'Cristián', 'Fernán', 'Raúl', 'Agustín'];
};
jsFiddle here.
Please notice that this only works for arrays of strings. If you want to filter a list of objects (and search in every property of every object, like Angular does) you'll have to enhance the filter function. I think this example should get you started.

JavaScript has a neat function for this, called localeCompare, where you can specify sensitivity = base, an option that makes it treat á and a as equivalent, but it is not widely supported. I think your only option is to create a filter function wherein you normalise both strings manually (replacing ó with o and so on) and compare the results.

Here is a slightly enhanced version (not counting the extra foreign characters it searches for, of course) of the above. I put it straight into my controller and it allowed me to search all the data that I wanted to search. Thanks Bernardo for your input into this!
Hope it helps somebody out.
function removeAccents(value) {
return value
.replace(/á/g, 'a')
.replace(/â/g, 'a')
.replace(/é/g, 'e')
.replace(/è/g, 'e')
.replace(/ê/g, 'e')
.replace(/í/g, 'i')
.replace(/ï/g, 'i')
.replace(/ì/g, 'i')
.replace(/ó/g, 'o')
.replace(/ô/g, 'o')
.replace(/ú/g, 'u')
.replace(/ü/g, 'u')
.replace(/ç/g, 'c')
.replace(/ß/g, 's');
}
$scope.ignoreAccents = function (item) {
if ($scope.search) {
var search = removeAccents($scope.search).toLowerCase();
var find = removeAccents(item.name + ' ' + item.description+ ' ' + item.producer+ ' ' + item.region).toLowerCase();
return find.indexOf(search) > -1;
}
return true;
};

The method, proposed by #Michael Benford has a big disadvantage: it is a stateful filter. This practice is strongly discouraged by angular. Plus, the method doesn’t work with deep arrays and objects.
I prefer to extend the standard angular filter:
HTML:
<div ng-app ng-controller="Ctrl">
<input type="text" ng-model="search">
<ul>
<li ng-repeat="person in people | filter: search : searchFn">{{ person.names }} {{ person.surnames }}</li>
</ul>
</div>
Javascript:
function Ctrl($scope) {
$scope.people = [{names: 'Jose', surnames: 'Benítez'}, {names: 'José María', surnames: 'Núñez Rico'}, {names: 'Rodrigo', surnames: 'Núñez'}];
$scope.searchFn = function(actual, expected) {
if (angular.isObject(actual)) return false;
function removeAccents(value) {
return value.toString().replace(/á/g, 'a').replace(/é/g, 'e').replace(/í/g, 'i').replace(/ó/g, 'o').replace(/ú/g, 'u').replace(/ñ/g, 'n');
}
actual = removeAccents(angular.lowercase('' + actual));
expected = removeAccents(angular.lowercase('' + expected));
return actual.indexOf(expected) !== -1;
}
}

Check here for solutions to filter a list of objects and search keywords in every property of every object. It also maintain angular like search and also search with/ without accent characters.
Following is the filter definition:-
// ignore accents filter
$scope.ignoreAccents = function (item) {
if (!$scope.search) return true;
var objects = [];
var jsonstr = JSON.stringify(item);
var parsejson = JSON.parse(jsonstr);
var searchterm = $scope.search.replace(/[!#$%&'()*+,-./:;?#[\\\]_`{|}~]/g, ''); // skip replace if not required (it removes special characters)
objects = getNoOfResults(parsejson, searchterm);
return objects.length > 0;
};

Related

Implementing rich text feature in Angularjs with angular-smiles.min.js

I am new to AngularJS and I am working on implementing rich texts for comments, bold, italic etc. I came across angular-smiles which is quiet easy and amazing to use.
<body ng-controller="SomeCtrl">
<p ng-bind-html="message | smilies "></p>
<div class="input-group">
<span class="input-group-addon"
smilies-selector="message"
smilies-placement="right"
smilies-title="Smilies"></span>
<textarea ng-model="message" focus-on-change="message" class="form-control"></textarea>
</div>
I also have to implement other features like ** to bold and keeping line breaks as <br> . Can someone please guide me on the angular way of doing it. A small hint with relevant topic is good enough to help me out as the project in hand has very limited time to complete.
Your best bet will be filters. I would highly recommend you to go through it.
now, just to help you out, I have written down a small code to help you grab it better.
app.controller('MainCtrl', function($scope,FILTER_FUNCTIONS) {
$scope.message = '';
// remove this,just to show you line breaks
$scope.$watch('message',function(newVal,oldVal){
console.log(newVal)
})
});
function f1(str){
var obj = { expr: /\n+?/g, value: '<br>' };
return str.replace(obj.expr, obj.value)
};
function f2(str){
var boldArray = str.split("**");
console.log(boldArray)
if(boldArray.length < 3){
return str;
}else{
for(var count = 0 ; count < boldArray.length ; count++){
if(count%2 !== 0 && (count+1 !== boldArray.length)){
boldArray[count] = '<strong>'+boldArray[count]+'</strong>'
}else if(count%2 !== 0){
boldArray[count] = '**'+boldArray[count]
}
}
return boldArray.join("");
}
}
var arr = [f1,f2];
app.value('FILTER_FUNCTIONS',arr);
app.filter('richText', function(FILTER_FUNCTIONS) {
return function(string) {
return FILTER_FUNCTIONS.reduce(function(result, someFn) {
return someFn(result);
}, string || '');
};
});
and in your html , add message | smilies | richText.
you can increase the rich text feature just by adding new functions in your array arr

AngularJS - Using custom filter in ng-repeat for prefixing comma

Need to remove comma if value is empty works good if I have value
present at start or middle; But same doesn't work in this scenario.
app.filter('isCSV', function() {
return function(data) {
return (data !== '') ? data + ', ' : '';
};
});
Angularjs ng repeat for addressline - Plunker
I would instead operate on arrays of properties and use a pair of filters, one to remove empty values, and one to join the array.
This way it's very explicit about what properties you are displaying.
<body ng-controller="MainCtrl">
<ul>
<li ng-repeat="item in details">
{{ [ item.address0, item.address1, item.address2, item.address3] | removeEmpties | joinBy:', ' }}
</li>
</ul>
</body>
With the following filters:
app.filter('removeEmpties', function () {
return function (input,delimiter) {
return (input || []).filter(function (i) { return !!i; });
};
});
app.filter('joinBy', function () {
return function (input,delimiter) {
return (input || []).join(delimiter || ',');
};
});
Here's the updated Plunkr
Tricky but should work in your case Also no filter need
{{ item.address0 }} <span ng-if="item.address1">,
</span> {{ item.address1}}<span ng-if="item.address2">,</span>{{
item.address2}}
<span ng-if="item.address3">,</span>{{ item.address3}}
Here is working example
I would prefer writing a function instead of adding a filter so many times.
$scope.mergeAddresses = function(item) {
var address = item.address0;
[1,2,3].forEach(function(i) {
var add = item["address"+i];
if (!add) return;
address += (address ? ", " : "") + add;
});
if (address) address += ".";
return address;
}
Plunker

AngularJS ng-repeat, comma separated with 'and' before the last item

I have a list of items ...
$scope.Users =[{
UserName: ''
}];
In my view I want to list them like this assuming I have only 4 items in my $scope:Users
Username1, Username2, Username3 and Username4
<span data-ng-repeat="user in Users">{{user.Username}}</span>{{$last ? '' : ', '}}
The above expression will basically add comma after each item and works fine.
My problem is how do I add an and keyword before the last item so it will be like:
Username1, Username2, Username3 and Username4
instead of:
Username1, Username2, Username3, Username4
$last is the truthy value.. so it holds either true or false and it doesn't hold the last element index..
I guess below expression should solve your problem
<p><span ng-repeat="user in Users">
{{user.Username}} {{$last ? '' : ($index==Users.length-2) ? ' and ' : ', '}}
</span></p>
Also make sure that you have the expression with $last within ng-repeat element and not outside of it
Please check the below working fiddle
http://jsfiddle.net/hrishi1183/Sek8F/2/
This could be one of the solutions
<span data-ng-repeat="user in Users">{{user.Username}}<font ng-show="!$last">,</font></span>
<span ng-repeat="user in Users">{{$first ? '' : $last ? ' and ' : ', '}}{{user.Username}}</span>
Instead of appending something prepend it. You can use $first to omit the first one. You can then use $last to add "and" instead of a comma.
Use a comma before and to promote clarity!
Bill Gates donates 6 million to Username1, Username2 and Username3.
vs
Bill Gates donates 6 million to Username1, Username2, and Username3.
Without the serial comma, the sentence does not clearly indicate that each of the users is to be given an equal share.
<span ng-repeat="user in Users">
{{user.Username}}{{$last ? '' : ($index==Username.length-2) ? ', and ' : ', '}}
</span>
Outputs:
Username1, Username2, Username3, and Username4
If you just need the text output, use a custom filter instead of ng-repeat:
<span>{{Users | humanizedUserList}}</span>
the filter code being something like this (using Lodash):
app.filter('humanizedUserList', function() {
return function(users) {
var last_users = _.last(users, 2);
return _.reduce(users, function(out, user, idx, users) {
out += user.UserName;
if(user === last_users[1]) { // last entry
return out;
}
else if(user === last_users[0]) { // second to last entry
return out + ', and ';
}
else {
return out + ', ';
}
});
};
}
You'd save yourself the hackish use of $last outside of the ng-repeat and ternary operators - and add reusability for other parts of your application.
I ran into this problem today, but with an extra challenge that the list items may need to be formatted within the sentence (for example, bold items or links). So just outputting a string from a filter wouldn't work. Initially I tried using ng-bind-html and outputting HTML from the filter, but that wasn't flexible enough.
I ended up making a directive that can be used within any ng-repeat to add the separator between list items. The tricky part is I only had access to $first, $last, and $index (not the original array or its length!).
My solution:
var app = angular.module('app', []);
app.directive('listSeparator', function() {
return {
replace: true,
template: '<span>{{ separator }}</span>',
link: function(scope, elem, attrs) {
scope.$watchGroup(["$index", "$first", "$last"], function() {
if (scope.$first)
scope.separator = "";
else if (scope.$last && scope.$index == 1)
scope.separator = " and ";
else if (scope.$last)
scope.separator = ", and ";
else
scope.separator = ",";
})
}
}
})
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.3.10/angular.min.js"></script>
<div ng-app="app">
Click a button to see the formatted list.
<button ng-click="myArray = ['one']">One item</button>
<button ng-click="myArray = ['one','two']">Two items</button>
<button ng-click="myArray = ['one','two','three']">Three items</button><br>
<span ng-repeat="item in myArray"><list-separator></list-separator>
<strong>{{item}}</strong></span>
</div>
Enjoy!

angularjs - filter by multiple models

This seems like it must be simple, I just cannot find the answer.
Let's say I have an array of data, set out like the following:
friends = [{name:'John', age:60, location:'Brighton', street:'Middle Street'},
{name:'Bob', age:5, location:'Brighton', street:'High Street'}];
Now, I want to filter the data based on a text input like so:
<input ng-model="searchText">
<ul>
<li ng-repeat="friend in friends | orderBy:'name' | filter:searchText">
{{friend.name}} - {{friend.location}}</li>
</ul>
This works fine but it filters the input text based on every attribute of the friend object (name, age, location and street). I'd like to be able to filter based on name and location only (ignoring age and street). Is this possible without a custom filter?
Yes, it's possible by simply passing a predicate to the filter instead of a string:
<li ng-repeat="friend in friends | orderBy:'name' | filter:friendContainsSearchText">
$scope.friendContainsSearchText = function(friend) {
return friend.name.indexOf($scope.searchText) >= 0 || friend.location.indexOf($scope.searchText) >= 0
}
Here is how we do it with a custom filter.
DEMO: http://plnkr.co/edit/q7tYjOvFjQHSR0QyGETj?p=preview)
[array] | search:query:columns:operator
> query: this is the term you are looking for
> columns: an array of the names of the properties you want to look for (if empty, will use the angular filter with query)
> operator: a boolean to switch between OR (true) and AND (false, default)
html
<ul>
<li ng-repeat="item in list | search:query:['name','location']:operator">
<pre>{{item | json}}</pre>
</li>
</ul>
js
app.filter('search', function($filter) {
return function(input, term, fields, operator) {
if (!term) {
return input;
}
fields || (fields = []);
if (!fields.length) {
return $filter('filter')(input, term);
}
operator || (operator = false); // true=OR, false=AND
var filtered = [], valid;
angular.forEach(input, function(value, key) {
valid = !operator;
for(var i in fields) {
var index = value[fields[i]].toLowerCase().indexOf(term.toLowerCase());
// OR : found any? valid
if (operator && index >= 0) {
valid = true; break;
}
// AND: not found once? invalid
else if (!operator && index < 0) {
valid = false; break;
}
}
if (valid) {
this.push(value);
}
}, filtered);
return filtered;
};
});
Alternatively you can use:
<li ng-repeat="friend in friends | orderBy:'name' | filter:{ name :searchText}">
You can put several filters just like ....
<div>
<input ng-model="Ctrl.firstName" />
<input ng-model="Ctrl.age" />
<li ng-repeat = "employee in Ctrl.employees | filter:{name:Ctrl.firstName} | filter:{age:Ctrl.age}">{{employee.firstName}}</li>
</div>

Highlighting a filtered result in AngularJS

I'm using a ng-repeat and filter in angularJS like the phones tutorial but I'd like to highlight the search results in the page. With basic jQuery I would have simply parsed the page on key up on the input, but I'm trying to do it the angular way. Any ideas ?
My code :
<input id="search" type="text" placeholder="Recherche DCI" ng-model="search_query" autofocus>
<tr ng-repeat="dci in dcis | filter:search_query">
<td class='marque'>{{dci.marque}} ®</td>
<td class="dci">{{dci.dci}}</td>
</tr>
In did that for AngularJS v1.2+
HTML:
<span ng-bind-html="highlight(textToSearchThrough, searchText)"></span>
JS:
$scope.highlight = function(text, search) {
if (!search) {
return $sce.trustAsHtml(text);
}
return $sce.trustAsHtml(text.replace(new RegExp(search, 'gi'), '<span class="highlightedText">$&</span>'));
};
CSS:
.highlightedText {
background: yellow;
}
angular ui-utils supports only one term. I'm using the following filter rather than a scope function:
app.filter('highlight', function($sce) {
return function(str, termsToHighlight) {
// Sort terms by length
termsToHighlight.sort(function(a, b) {
return b.length - a.length;
});
// Regex to simultaneously replace terms
var regex = new RegExp('(' + termsToHighlight.join('|') + ')', 'g');
return $sce.trustAsHtml(str.replace(regex, '<span class="match">$&</span>'));
};
});
And the HTML:
<span ng-bind-html="theText | highlight:theTerms"></span>
Try Angular UI
Filters -> Highlite (filter).
There is also Keypress directive.
index.html
<!DOCTYPE html>
<html>
<head>
<script src="angular.js"></script>
<script src="app.js"></script>
<style>
.highlighted { background: yellow }
</style>
</head>
<body ng-app="Demo">
<h1>Highlight text using AngularJS.</h1>
<div class="container" ng-controller="Demo">
<input type="text" placeholder="Search" ng-model="search.text">
<ul>
<!-- filter code -->
<div ng-repeat="item in data | filter:search.text"
ng-bind-html="item.text | highlight:search.text">
</div>
</ul>
</div>
</body>
</html>
app.js
angular.module('Demo', [])
.controller('Demo', function($scope) {
$scope.data = [
{ text: "<< ==== Put text to Search ===== >>" }
]
})
.filter('highlight', function($sce) {
return function(text, phrase) {
if (phrase) text = text.replace(new RegExp('('+phrase+')', 'gi'),
'<span class="highlighted">$1</span>')
return $sce.trustAsHtml(text)
}
})
Reference : http://codeforgeek.com/2014/12/highlight-search-result-angular-filter/
demo : http://demo.codeforgeek.com/highlight-angular/
I hope my light example will make it easy to understand:
app.filter('highlight', function() {
return function(text, phrase) {
return phrase
? text.replace(new RegExp('('+phrase+')', 'gi'), '<kbd>$1</kbd>')
: text;
};
});
<input type="text" ng-model="search.$">
<ul>
<li ng-repeat="item in items | filter:search">
<div ng-bind-html="item | highlight:search.$"></div>
</li>
</ul>
There is standart Highlight filter in the angular-bootstrap: typeaheadHighlight
Usage
<span ng-bind-html="text | typeaheadHighlight:query"></span>
With scope {text:"Hello world", query:"world"} renders in
<span...>Hello <strong>world</strong></span>
Going off of #uri's answer in this thread, I modified it to work with a single string OR a string array.
Here's the TypeScript version
module myApp.Filters.Highlight {
"use strict";
class HighlightFilter {
//This will wrap matching search terms with an element to visually highlight strings
//Usage: {{fullString | highlight:'partial string'}}
//Usage: {{fullString | highlight:['partial', 'string, 'example']}}
static $inject = ["$sce"];
constructor($sce: angular.ISCEService) {
// The `terms` could be a string, or an array of strings, so we have to use the `any` type here
/* tslint:disable: no-any */
return (str: string, terms: any) => {
/* tslint:enable */
if (terms) {
let allTermsRegexStr: string;
if (typeof terms === "string") {
allTermsRegexStr = terms;
} else { //assume a string array
// Sort array by length then join with regex pipe separator
allTermsRegexStr = terms.sort((a: string, b: string) => b.length - a.length).join('|');
}
//Escape characters that have meaning in regular expressions
//via: http://stackoverflow.com/a/6969486/79677
allTermsRegexStr = allTermsRegexStr.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
// Regex to simultaneously replace terms - case insensitive!
var regex = new RegExp('(' + allTermsRegexStr + ')', 'ig');
return $sce.trustAsHtml(str.replace(regex, '<mark class="highlight">$&</mark>'));
} else {
return str;
}
};
}
}
angular
.module("myApp")
.filter("highlight", HighlightFilter);
};
Which translates to this in JavaScript:
var myApp;
(function (myApp) {
var Filters;
(function (Filters) {
var Highlight;
(function (Highlight) {
"use strict";
var HighlightFilter = (function () {
function HighlightFilter($sce) {
// The `terms` could be a string, or an array of strings, so we have to use the `any` type here
/* tslint:disable: no-any */
return function (str, terms) {
/* tslint:enable */
if (terms) {
var allTermsRegexStr;
if (typeof terms === "string") {
allTermsRegexStr = terms;
}
else {
// Sort array by length then join with regex pipe separator
allTermsRegexStr = terms.sort(function (a, b) { return b.length - a.length; }).join('|');
}
//Escape characters that have meaning in regular expressions
//via: http://stackoverflow.com/a/6969486/79677
allTermsRegexStr = allTermsRegexStr.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
// Regex to simultaneously replace terms - case insensitive!
var regex = new RegExp('(' + allTermsRegexStr + ')', 'ig');
return $sce.trustAsHtml(str.replace(regex, '<mark class="highlight">$&</mark>'));
}
else {
return str;
}
};
}
//This will wrap matching search terms with an element to visually highlight strings
//Usage: {{fullString | highlight:'partial string'}}
//Usage: {{fullString | highlight:['partial', 'string, 'example']}}
HighlightFilter.$inject = ["$sce"];
return HighlightFilter;
})();
angular.module("myApp").filter("highlight", HighlightFilter);
})(Highlight = Filters.Highlight || (Filters.Highlight = {}));
})(Filters = myApp.Filters || (myApp.Filters = {}));
})(myApp|| (myApp= {}));
;
Or if you just want a simple JavaScript implementation without those generated namespaces:
app.filter('highlight', ['$sce', function($sce) {
return function (str, terms) {
if (terms) {
var allTermsRegexStr;
if (typeof terms === "string") {
allTermsRegexStr = terms;
}
else {
// Sort array by length then join with regex pipe separator
allTermsRegexStr = terms.sort(function (a, b) { return b.length - a.length; }).join('|');
}
//Escape characters that have meaning in regular expressions
//via: http://stackoverflow.com/a/6969486/79677
allTermsRegexStr = allTermsRegexStr.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
// Regex to simultaneously replace terms - case insensitive!
var regex = new RegExp('(' + allTermsRegexStr + ')', 'ig');
return $sce.trustAsHtml(str.replace(regex, '<mark class="highlight">$&</mark>'));
}
else {
return str;
}
};
}]);
EDITED to include a fix that would have previously broken this is someone searched for . or any other character that had meaning in a regular expression. Now those characters get escaped first.
Use ng-class that is applied when the search term is related to the data the element contains.
So on your ng-repeated elements, you'd have ng-class="{ className: search_query==elementRelatedValue}"
which would apply class "className" to elements dynamically when the condition is met.
My solution for highlight, used this with angular-ui-tree element: https://codepen.io/shnigi/pen/jKeaYG
angular.module('myApp').filter('highlightFilter', $sce =>
function (element, searchInput) {
element = element.replace(new RegExp(`(${searchInput})`, 'gi'),
'<span class="highlighted">$&</span>');
return $sce.trustAsHtml(element);
});
Add css:
.highlighted {
color: orange;
}
HTML:
<p ng-repeat="person in persons | filter:search.value">
<span ng-bind-html="person | highlightFilter:search.value"></span>
</p>
And to add search input:
<input type="search" ng-model="search.value">
About the problems with special caracter, I think just escaping you might lose regex search.
What about this:
function(text, search) {
if (!search || (search && search.length < 3)) {
return $sce.trustAsHtml(text);
}
regexp = '';
try {
regexp = new RegExp(search, 'gi');
} catch(e) {
return $sce.trustAsHtml(text);
}
return $sce.trustAsHtml(text.replace(regexp, '<span class="highlight">$&</span>'));
};
An invalid regexp could be user just typing the text:
valid: m
invalid: m[
invalid: m[ô
invalid: m[ôo
valid: m[ôo]
valid: m[ôo]n
valid: m[ôo]ni
valid: m[ôo]nic
valid: m[ôo]nica
What do you think #Mik Cox?
Another proposition:
app.filter('wrapText', wrapText);
function wrapText($sce) {
return function (source, needle, wrap) {
var regex;
if (typeof needle === 'string') {
regex = new RegExp(needle, "gi");
} else {
regex = needle;
}
if (source.match(regex)) {
source = source.replace(regex, function (match) {
return $('<i></i>').append($(wrap).text(match)).html();
});
}
return $sce.trustAsHtml(source);
};
} // wrapText
wrapText.$inject = ['$sce'];
// use like this
$filter('wrapText')('This is a word, really!', 'word', '<span class="highlight"></span>');
// or like this
{{ 'This is a word, really!' | wrapText:'word':'<span class="highlight"></span>' }}
I'm open to criticism ! ;-)
Thanks for asking this as it was something I was dealing with as well.
Two things though:
First, The top answer is great but the comment on it is accurate that highlight() has problem with special characters. That comment suggests using an escaping chain which will work but they suggest using unescape() which is being phased out. What I ended up with:
$sce.trustAsHtml(decodeURI(escape(text).replace(new RegExp(escape(search), 'gi'), '<span class="highlightedText">$&</span>')));
Second, I was trying to do this in a data bound list of URLs. While in the highlight() string, you don't need to data bind.
Example:
<li>{{item.headers.host}}{{item.url}}</li>
Became:
<span ng-bind-html="highlight(item.headers.host+item.url, item.match)"></span>
Was running into problems with leaving them in {{ }} and getting all sorts of errors.
Hope this helps anybody running into the same problems.
If you are using the angular material library there is a built in directive called md-highlight-text
From the documentation:
<input placeholder="Enter a search term..." ng-model="searchTerm" type="text">
<ul>
<li ng-repeat="result in results" md-highlight-text="searchTerm">
{{result.text}}
</li>
</ul>
Link to docs: https://material.angularjs.org/latest/api/directive/mdHighlightText

Resources