Firedrake969
Firedrake969

Reputation: 773

Populate table from JSON with search

I was able to purely implement a grid from a JSON object - AngularJS ng-repeat to populate grid from array. However, due to the nature of the added indices, being able to create a search bar with ng-model and filter:search does not work - it only can search for the first in each table row.

var test= angular.module("app", []);

test.controller("appControl", function($scope, $http) {
	$http.get("http://www.w3schools.com/angular/customers.php")
		.success(function (response) {
			$scope.data = response.records;
		}
	);
    $scope.getFiltered= function(obj, idx){
       //Set a property on the item being repeated with its actual index
       //return true only for every 1st item in 5 items
       return !((obj._index = idx) % 5);
    }
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
<body ng-app='app' ng-controller='appControl'>
    <input type='text' ng-model='search.Country' />
    <table>
        <tr ng-repeat="work in data | filter:getFiltered | filter:search">
            <td>{{work.Country}}</td>
            <td>{{data[work._index+1].Country}}</td>
            <td>{{data[work._index+2].Country}}</td>
            <td>{{data[work._index+3].Country}}</td>
            <td>{{data[work._index+4].Country}}</td>
        </tr>
    </table>
</body>

The length of data may or not cause the table to look like a perfect rectangle.

I'm working on making a function to split up the array and create the grid in JavaScript itself, but I'm still not sure how to filter it via search input.

Second try (with the mentioned function, but no filters at all yet...):

var test= angular.module("app", []);

function createGrid(arr, width) {
    newArr = [];
    reps = Math.ceil(arr.length/width) * width;
    k = 0;
    for (var i = 0; i < reps/width; i++) {
        newArr[i] = [];
    }
    
    for (var i = 0; i < reps/width; i++) {
        for (var j = 0; j < width; j++) {
            (arr[k]) ? newArr[i][j] = arr[k] : newArr[i][j] = "";
            //console.log(i, j, arr[k]);
            k++;
        }
    }
    
    return newArr;
}

test.controller("appControl", function($scope, $http) {
    $scope.gridWidth = 4;
	$http.get("http://www.w3schools.com/angular/customers.php")
		.success(function (response) {
			$scope.data = createGrid(Object.keys(response.records).map(function(k) { return response.records[k] }), $scope.gridWidth);
		}
	);
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
<body ng-app='app' ng-controller='appControl'>
    <input type='text' ng-model='search.Country' />
    <table>
        <tr ng-repeat="row in data">
            <td ng-repeat='work in row'>
                {{ work.Country }}
            </td>
        </tr>
    </table>
</body>

Upvotes: 1

Views: 1368

Answers (2)

Rendy Del Rosario
Rendy Del Rosario

Reputation: 1297

You could try something like this:

var test= angular.module("app", []);
  
test.controller("appControl", function($scope, $http) {

	$http.get("http://www.w3schools.com/angular/customers.php")
		.success(function (response) {
	         $scope.data = response.records;
                 $scope.filteredData= response.records;
		}
	);

     $scope.$watch('search', function () {

      var array=[];
      for(var i in $scope.data)
      {
          if($scope.search==undefined || $scope.search.length == 0 ||  ($scope.data[i].Country!=undefined&&$scope.data[i].Country.toUpperCase().startsWith($scope.search.toUpperCase()))){
             array.push($scope.data[i]);
          }
      }
      $scope.filteredData=array;
    });

    $scope.getFiltered= function(obj, idx){
       //Set a property on the item being repeated with its actual index
       //return true only for every 1st item in 3 items
       return !((obj._index = idx) % 5);
    }
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
<body ng-app='app' ng-controller='appControl'>
    <input type='text' ng-model='search' />
    <table>
        <tr ng-repeat="work in filteredData | filter:getFiltered | filter:search">
            <td>{{work.Country}}</td>
            <td ng-show="filteredData[work._index+1]">{{filteredData[work._index+1].Country}}</td>
            <td ng-show="filteredData[work._index+2]">{{filteredData[work._index+2].Country}}</td>
            <td ng-show="filteredData[work._index+3]">{{filteredData[work._index+3].Country}}</td>
            <td ng-show="filteredData[work._index+4]">{{filteredData[work._index+4].Country}}</td>
        </tr>
    </table>
</body>

Upvotes: 3

Rias
Rias

Reputation: 1996

You could prefilter the items after a successful Ajax call and every time your model search changes.

  1. Save the previously filtered items into $scope.workers.
  2. Use $scope.$watch to watch for changes in the model search
  3. Use the function searched(data) to filter for the entries that have characters given in the search field using the indexOf method. If the filter is empty, also show every item (typeof $scope.search == 'undefined').
  4. If you want the search be case insensitive, transform searchand the Country .toLowerCase(), when using .indexOf()

Then you will only need one Angular filter $scope.getFiltered(), which makes sure, that the entries are in rows of five.

var test= angular.module("app", []);

test.controller("appControl", function($scope, $http) {
	$http.get("http://www.w3schools.com/angular/customers.php")
		.success(function (response) {
			$scope.data = response.records;
            $scope.workers = $scope.searched($scope.data);
		}
	);

    $scope.getFiltered= function(obj, idx){
       //Set a property on the item being repeated with its actual index
       //return true only for every 1st item in 5 items
       return !((obj._index = idx) % 5);
    };
  
    $scope.searched = function (data) {
      var array = [];
      var max = 0;
      
      if (typeof data === 'object') {
        max = data.length;
      }
      
      for (var i = 0; i < max; i += 1) {
        if (typeof $scope.search == 'undefined' || data[i].Country.toLowerCase().indexOf($scope.search.toLowerCase()) != -1) {
          array.push(data[i]);
        }
      }
      
      return array;
    
    };

    $scope.$watch('search', function () {
      $scope.workers = $scope.searched($scope.data);
    })
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
<body ng-app='app' ng-controller='appControl'>
    <input type='text' ng-model='search' />
    <table>
        <tr ng-repeat="work in workers | filter:getFiltered">
            <td>{{ work.Country }}</td>
            <td>{{ workers[$index+1].Country }}</td>
            <td>{{ workers[$index+2].Country }}</td>
            <td>{{ workers[$index+3].Country }}</td>
            <td>{{ workers[$index+4].Country }}</td>
        </tr>
    </table>
</body>

Upvotes: 2

Related Questions