Search code examples
javascriptangularjsangularjs-filtersmart-table

AngularJS Smart Table filtering special characters with a space when displaying all rows


I am running a few tables that use the pipe/ajax section of the code with the controller/service setup. https://lorenzofox3.github.io/smart-table-website/#section-pipe

One of the issues I am coming across is when there are special characters in the values with a space in it and it is unable to filter it. For example, if there was a lastname of "last-name firstname" it is unable to filter the data but it is able to filter the name "last-name" and it is able to do "lastname firstname" just fine.

Could I get some help on figuring out why this might not be able to filter correctly?

Thank You!

Edit: I noticed I forgot to add the filter.

app.filter('propsFilter', function() {
  return function(items, props) {
    var out = [];

    if (angular.isArray(items)) {
      var keys = Object.keys(props);

      items.forEach(function(item) {
        var itemMatches = false;

        for (var i = 0; i < keys.length; i++) {
          var prop = keys[i];
          var text = props[prop].toLowerCase();
          if (item[prop].toString().toLowerCase().indexOf(text) !== -1) {
            itemMatches = true;
            break;
          }
        }

        if (itemMatches) {
          out.push(item);
        }
      });
    } else {
      // Let the output be the input untouched
      out = items;
    }

    return out;
  };
});

app.controller('mainCtrl', ['$scope', '$window', 'Resource', function($scope, $window, service) {

    var ctrl = this;

    this.displayed = [];

    $scope.itemsByPage = $window.datatableperPage;

    this.callServer = function callServer(tableState) {

        ctrl.isLoading = true;

        var pagination = tableState.pagination;

        var start = pagination.start || 0;
        var number = pagination.number || 10;

        service.getPage(start, number, tableState).then(function(result) {
            ctrl.displayed = result.data;
            tableState.pagination.numberOfPages = result.numberOfPages; //set the number of pages so the pagination can update
            ctrl.isLoading = false;
        });
    };

}]);
app.factory('Resource', ['$q', '$filter', '$window', '$http', '$timeout', function($q, $filter, $window, $http, $timeout) {

    var nameData = [];

    $http.get($window.datatableSource).success(function(response) {
        nameData = response;
    });

    function getPage(start, number, params) {

        var deferred = $q.defer();

        var filtered = params.search.predicateObject ? $filter('filter')(nameData, params.search.predicateObject) : nameData;

        if (params.sort.predicate) {
            filtered = $filter('orderBy')(filtered, params.sort.predicate, params.sort.reverse);
        }

        var result = filtered.slice(start, start + number);

        $timeout(function() {
            //note, the server passes the information about the data set size
            deferred.resolve({
                data: result,
                numberOfPages: Math.ceil(filtered.length / number),
            });
        }, $window.datatableTimeout);

        return deferred.promise;
    }

    return {
        getPage: getPage
    };


}]);

Update:

With Hardy's Help I was finally able to replicate the issue.

When setting the

$scope.itemsByPage = -1;

the filtered results seem to vanish after initial couple characters at the slice

result = filtered.slice(start, start + number); 

In this example, I added the word "Clinical - " to the beginning of a name and it is unable to search for the word when you start typing the word "Clinical" but other words work just fine.

https://plnkr.co/edit/7n68AKbwQGpVdFOpbUuP?p=preview


Solution

  • Okay, I've traced all the functions and the problem in Plunker is in this very line. Try to change the value to any positive integer and you will see that your app works just fine.

    $scope.itemsByPage = -1;
    

    The reason you get strange filtering results in some cases is because this very value is used as number later in

    var result = filtered.slice(start, start + number);
    

    thus translating to

    var result = filtered.slice(0, -1);
    

    .slice(0, -1) returns a shallow copy of the filtered array excluding the last item. And when you only have one filtered result you will recieve an empty array.

    Voilà!


    Update

    As it turns out, the whole reason of using $scope.itemsByPage = -1 was a delusion of the behaviour of the library in that case.
    The desired behavior was to "always return all the rows" and it can be easily achieved by using Infinity

    $scope.itemsByPage = Infinity
    

    This way we will get

    var result = filtered.slice(0, Infinity);
    

    thus getting initial filtered array in the output.