Well, I have this plunkr trying to simulate my situation:
The idea is that the user type a word on the textbox, and when click the button, an angular service returns an answer (result) from a DB according to the typed on the textbox (I have simulated this process with requesting data to a json file, so it is not important whatever you type, always will return the whole data) and populated a table.
But now, I'm working with the filter search. In this textbox, you can search for a person defined by:
- first_name
- middle_name
- first_surname
- second_surname
I have implemented two kind of visual filter:
1) Visual Filter for hiding and showing results: (defined in appCtrl.js)
$scope.changedValue=function(){
var condition = $scope.filter.condition;
$scope.Model.filteredlist = filterFilter($scope.Model.expenses,function(value, index, array){
var fullname = (value.first_name+' '+value.middle_name+' '+value.first_surname+' '+value.second_surname).toLowerCase();
if (fullname.indexOf(condition.replace(/\s\s+/g, ' ').toLowerCase()) > -1 ) {
return array;
}
});
if (typeof $scope.Model.filteredlist != 'undefined') { // When page loads for first time
$scope.setPage();
}
}
2) Visual Filter for highlight the results: (defined in appDrct.js)
app.directive('highLight', function ($document, $sce) {
var component = function(scope, element, attrs) {
if (!attrs.highlightClass) {
attrs.highlightClass = 'angular-highlight';
}
var replacer = function(match, item) {
return '<span class="'+attrs.highlightClass+'">'+match+'</span>';
}
var tokenize = function(keywords) {
keywords = keywords.replace(new RegExp(',$','g'), '').split(' ');
var i;
var l = keywords.length;
for (i=0;i<l;i++) {
keywords[i] = keywords[i].replace(new RegExp('^ | $','g'), '');
}
return keywords;
}
scope.$watch('keywords', function(newValue, oldValue) {
console.log("new: " + newValue + " old " + oldValue);
var tokenized = tokenize(newValue);
var regex = new RegExp(tokenized.join('|'), 'gmi');
if(newValue.length>=1 || oldValue.length>=1){
for(i=0;i<=1;i++){
element[0].cells[i].innerHTML = element[0].cells[i].innerText.replace(regex, replacer);
}
}
});
}
return {
link: component,
replace: false,
scope: {
keywords: '=highLight'
}
};
});
The html calling those filters: (defined in table.html)
<input type="text" class="form-control" id="filter-list" placeholder="Name(s) and/or Lastname(s)" ng-model="filter.condition" ng-change="changedValue()">
......
<tr ng-repeat="expense in Model.filteredlist | pagination: pagination.currentPage : numPerPage" x-high:light="filter.condition">
<td>{{expense.first_name}} {{expense.middle_name}}</td>
<td>{{expense.first_surname}} {{expense.second_surname}}</td>
<td>{{expense.age}}</td>
</tr>
But I got some problems, because sometimes the person don't have middle_name or sometimes don't have second_surname.
To reproduce my issue, type in the search box: Lora and then erase it, and you will see that some data it is not rendered in the correct way. And if you type Loras and the erase the s the word don't highlight again, but if you continue erasing, the word highlight again.
So, what I'm doing wrong? I think it's a problem with the $scope.changeValue
filter, but I'm lost.
Any ideas?