Error in custom filter - javascript

I am getting the below error while using angular.js filter methos.
Error:
TypeError: Cannot read property 'length' of undefined
at adminCustomerViewController.js:1387
at fn (eval at compile (angularjs.js:212), <anonymous>:4:464)
at dirPagination.js:100
at Object.<anonymous> (angularjs.js:115)
at n.$digest (angularjs.js:130)
at n.$apply (angularjs.js:133)
at g (angularjs.js:87)
at K (angularjs.js:91)
at XMLHttpRequest.z.onload (angularjs.js:92)
I am explaining my code below.
<input class="form-control" placeholder="Type Restaurant Name" name="q" type="text" ng-model="letter">
<tr dir-paginate="cus in ($parent.labelResults=(listOfCustomerData | startsWithLetter:letter | orderBy:'rest_name')) | itemsPerPage:5 track by $index" current-page="currentPage">
<td>{{itemsPerPage *(currentPage-1)+$index+1}}</td>
<td>{{cus.rest_name}}</td>
</tr>
</tbody>
My controller side code is given below.
customerView.filter('startsWithLetter', function () {
return function (items, letter) {
//console.log('items',items);
var filtered = [];
var letterMatch = new RegExp(letter, 'i');
for (var i = 0; i < items.length; i++) {
var item = items[i];
if (letterMatch.test(item.rest_name.substring(0, 1))) {
filtered.push(item);
}
}
return filtered;
};
});
customerView.controller('adminCustomerViewController',function($scope,$state,$http,$window,$timeout,Upload,focusInputField){
$http({
method:'GET',
url:"php/customerInfo.php?action=disp",
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
}).then(function successCallback(response){
console.log('res',response.data);
$scope.listOfCustomerData=response.data;
},function errorCallback(response) {
})
})
Actually i am implementing the search functionality here . Here my requirement is when user will type at least first letter of the restaurant name(i.e-rest_name) the related restaurant will filter from the table. Suppose i have many restaurant like Anjum,A&P Chinese Food Express,Bookers BBQ & Crab Shack,Butcher And The Baker, Cactus Club Stephen Avenue,Cactus Club - Macleod Trail. Here when user is typing only a inside the search box the names started with a should filter . I did something but got the above error.Please help me.

Since you want only those objects that have the corresponding letters to input
you don't need to use Regexp.
Here a snippet working:
var app = angular.module('app', [])
.controller('mainCtrl', function($scope) {
$scope.countries = [
{
"name":"USA"
},
{
"name":"Japan"
},
{
"name":"France"
},
{
"name":"Canada"
},
{
"name":"China"
}
];
})
.filter('startsWith', function() {
return function(items, search) {
if (!search) {
return items;
}
search = search.toLowerCase();
return items.filter(function(element) {
return element.name.toLowerCase().substring(0, search.length).indexOf(search) != -1;
});
}
});
<!DOCTYPE html>
<html ng-app="app">
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.7/angular.min.js"></script>
</head>
<body ng-controller="mainCtrl">
<label for="letter">Filter: </label>
<input type="text" id="letter" ng-model="letter">
<hr>
<table>
<thead>
<tr>
<th>Name</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="country in countries | startsWith: letter">
<td ng-bind="country.name"></td>
</tr>
</tbody>
</table>
</body>
</html>

Try this
<input class="form-control" placeholder="Type Restaurant Name" name="q" type="text" ng-model="letter">
<tr dir-paginate="cus in ($parent.labelResults=(listOfCustomerData | filter : letter )) | itemsPerPage:5 track by $index" current-page="currentPage">
<td>{{itemsPerPage *(currentPage-1)+$index+1}}</td>
<td>{{cus.rest_name}}</td>
</tr>
</tbody>
its best to use filter given in angular as comapred to make your custom filter

Related

Custom Service not giving desired result in controller in AngularJS 1.8

I have to debug a snippet written in AngularJS.
//===== service ==
app.service('allUserService', function($http) {
var config = {
headers: {
'X-XSRF-TOKEN': gettingValueFromSomewhere()
}
};
this.getAll = function() {
var restUrl = CONTEXT_PATH + '/rest/path/mypath';
return $http.get(restUrl, config).then(function(response) {
console.log(response.data.body); // console prints an Array which is correct
return response.data.body;
});
}
});
//========= controller ====
app.controller('UserCtrl', function($scope,allUserService) {
var valueArray = [];
valueArray = allUserService.getAll();
console.log(valueArray);
$scope.faqBook = valueArray;
});
allUserService :I am getting correct result from Rest webservie and console log shows desired return (an Array)
faqUserCtrl : I am not getting desired value in console log. Pls help me in finding the issue. It should have an array. I am expecting an Array in $scope.faqBook.
Important to Note, when I return a hardcoded array from allUserService, the code works fine
<div class="container" ng-app="UserModule" ng-controller="UserCtrl">
<p>Search : <input type="text" ng-model="search"/></p>
<table id="mainTable" class="table table-striped table-hover">
<tr ng-repeat="x in faqBook | filter:search">
<td><ul class="list-group"><li class="list-group-item">Question: {{ x.question }}</li><li class="list-group-item"> Answer: {{ x.answer }}</li></ul></td>
</tr>
</table>
</div>

<td ng-repeat="x in names |orderBy:'-Hindi' | limitTo:1"> {{x.name}} The marks should update if a user edits any single slot of data

I am trying to change the code that every time a user edits the marks in English or Hindi and then the highest Hindi and/or English marks are updated accordingly
CONTROLLER CODE
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope)
{
$scope.names = [
{name:'Priya',age:'19',gender:'Female',English:x[0], Hindi:x[1]},
....
....
{name:'Dev', age:'18' ,gender:'Male',English:x[2] ,Hindi:x[3]},
];
$scope.sum = function(list)
{
var total=0;
angular.forEach(list , function(x){
total+= x[];
});
return total;
}
});
HTML CODE
This is the code I use currently for displaying the highest marks
<tr ng-repeat ="x in names | orderBy:'sortColumn'">
<td>{{x.name}}</td>
<td>{{x.age}}</td>
<td>{{x.gender}}</td>
<td><input type="text" ng-model="x.English"></td>
<td><input type="text" ng-model="x.Hindi"></td>
<td ng-bind="avg=(x.English+x.Hindi)/2">{{avg}}</td>
<td>
<button>Delete</button>
</td>
</tr>
</table>
<table ng-model="sum">
<tr><td>The total is: <input value="{{sum(x)}}"></td></tr>
**<tr><td>THIS IS WHERE I WANT TO DISPLAY HIGHEST MARKS IN ENGLISH</td></tr>**
**<tr><td>**<td ng-repeat="x in names |orderBy:'-Hindi' | limitTo:1"> {{x.name}}THIS IS WHERE I WANT TO DISPLAY HIGHEST MARKS IN HINDI</td></tr>**
</table>
You can put watch on array like below:
$scope.total = 0
$scope.$watch('names', function(newVal) {
var total = 0;
angular.forEach(newVal, function(x) {
total += parseInt(x.English) + parseInt(x.Hindi);
});
$scope.total = total
}, true);
and in template replace {{sum(x)}} with {{total}}.
Check working example here

How to add regEx in angular filter

Example: plunker
From the above example, I have created a simple form with filter option using angular.
As far as the filter concern, it's a default filter which is provided by angular. Currently, when I search the text "br", it shows the id 1 and 10.
I would like to add the regEx in the search input.The search can be done using regEx.
what I need is, The search item can be
"br" => It show two data,
"b*" => Show all the data starts with b.
"*" => All the data
"*br" => All the data ends with br.
The above search should show the relevant data as per the search input.
scripts.js
var app = angular.module('app',[]);
app.controller('regEx', function($scope, $http) {
$scope.init = function() {
$http.get('https://jsonplaceholder.typicode.com/users/').success(function(data) {
$scope.data = data;
console.log(data);
}).error(function(e) {
console.log(e);
});
}
index.html
<!DOCTYPE html>
<html ng-app="app">
<head>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/css/bootstrap.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.0/angular.min.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body>
<div ng-controller="regEx" class="container">
<h1>RegEx in Angular search</h1>
<input type="text" class="form-control" ng-model="search" autofocus>
<br />
<table ng-init="init()" class="table table-bordered animated fadeIn">
<thead>
<tr>
<th>Id</th>
<th>Name</th>
<th>Phone Number</th>
<th>username</th>
<th>website</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="d in data | filter:search">
<td>{{d.id}}</td>
<td>{{d.name}}</td>
<td>{{d.phone}}</td>
<td>{{d.username}}</td>
<td>{{d.website}}</td>
</tr>
<tr ng-if="d.length < 1">
<td colspan="5" class="text-center">No Router Found</td>
</tr>
</tbody>
</table>
</div>
</body>
</html>
In this case I would probably create a custom filter.
The tricky part here is that your object model is not flat, so we have to do a deep traversal to check the fields. The caveat to this approach is that you could potentially be checking against fields that are not visible (although i believe this is how the default angular filter behaves).
If that is an issue, you could adjust the filter to pass in a list of fields to check against and use those to filter out unwanted fields.
Here is the filter :
app.filter('wildcard', function() {
return function(list, value) {
if (!value) {
return list;
}
var escaped = value.replace(/([.+?^=!:${}()|\[\]\/\\])/g, "\\$1");
var formatted = escaped.replace('*', '.*')
if (formatted.indexOf('*') === -1) {
formatted = '.*' + formatted + '.*'
}
var output = []
angular.forEach(list, function(item) {
var regex = new RegExp('^' + formatted + '$', 'im');
if (traverse(item, regex)) {
output.push(item);
}
});
return output
}
function traverse(item, regex) {
for (var prop in item) {
//angular property like hash
if(prop[0] === '$$'){
return;
}
var value = item[prop];
if (typeof value === 'object') {
traverse(value, regex);
}
if(regex.test(value)){
return true;
}
}
}
})
And then in you html :
<tr ng-repeat="d in data | wildcard:search">
Here is the plunker

Setting table with object in angular

I have an object I want to put in a table.
the object seems like: {"text":"111","order":["1","2","3","4","5"]}
there may be array as well as simple strings.
So how can I put this object in a table if I want the table to look like this:
property value
text 111
order 1,2,3,4,5
My table shows in the value column ["1","2","3","4","5"] instead of 1,2,3,4,5.
Here is what I wrote:
<tr data-ng-repeat="(key,val) in object">
<td>
{{ key }}
</td>
<td>
{{val}}
</td>
</tr>
I also tried with ng-swtich but it didn't work.
Here is a sample which checks if the value is an Array and joins them as a string.
Html:
<tr data-ng-repeat="(key,val) in object">
<td>
{{ key }}
</td>
<td>
{{val | isArray}}
</td>
</tr>
Controller:
app.controller('MainCtrl', function($scope) {
$scope.object = {"text":"111","order":["1","2","3","4","5"]};
});
app.filter("isArray", function() {
return function(input) {
var isArray = angular.isArray(input);
if(isArray)
return input.join();
return input;
};
});
Working code here
Is this what you were after?
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<table ng-app="app" ng-controller="MyTableController">
<tr data-ng-repeat="(key,val) in data">
<td>
{{ key }}
</td>
<td >
{{ val | join: ', ' }}
</td>
</tr>
</table>
<script>
angular.module('app', [])
// Filter that joins the input with the supplied separator
.filter('join', function () {
return function (value, separator) {
if (typeof value.join === 'function') {
return value.join(separator);
} else {
return value;
}
}
})
.controller('MyTableController', function ($scope) {
$scope.data = {"text":"111","order":["1","2","3","4","5"] };
});
</script>

Apply ng-class to array of items in angularjs

I am trying to highlight multiple row select functionality, so that when a user click's on a row it highlight the row and when it again select that row it un-highlight that. But the problem I am facing is how to give array of items to ng-class.
Here is my code.
<tr ng-click="selectRow(1)" ng-class="{row_selected: ArrayOfItems}" class="ng-scope odd">
<td class="">
test
</td>
</tr>
And in my controller
$scope.selectedArray = [];
$scope.selectRow = function(id) {
if($scope.selectedArray.indexOf(id) == -1) {
$scope.selectedArray.push(id);
}else {
$scope.selectedArray.splice($scope.selectedArray.indexOf(id),1);
}
});
So what I am doing in controller is on clicking a row it push the id's in an array and on clicking the same row it pops out that id from array.
Any help ?
First check whether the row is selected or not
<tr ng-click="selectRow(1)" ng-class="{row_selected: isRowSelected(1)}" class="ng-scope odd">
<td class="">
test
</td>
</tr>
Add the isRowSelected to controller:
$scope.selectedArray = [];
$scope.isRowSelected = function(id) {
$scope.selectedArray.indexOf(id) != -1
}
$scope.selectRow = function(id) {
if($scope.selectedArray.indexOf(id) == -1) {
$scope.selectedArray.push(id);
}else {
$scope.selectedArray.splice($scope.selectedArray.indexOf(id),1);
}
});
More proper setup would be with in use of 'ng-repeat'. See the working code at:
JSFiddle
HTML:
<div ng-controller="MyController">
<table>
<tr ng-repeat="item in items" ng-click="selectRow(item)" ng-class="{row_selected: isSelected(item)}">
<td>
<a id="{{item}}">test {{item}}</a>
</td>
</tr>
</table>
</div>
JS/AngularJS:
var myApp = angular.module('myApp', []);
myApp.controller('MyController', ['$scope', function ($scope) {
$scope.items = [1,2,3,4,5];
$scope.selectedArray = [];
$scope.selectRow = function (id) {
if($scope.selectedArray.indexOf(id) == -1) {
$scope.selectedArray.push(id);
}else {
$scope.selectedArray.splice($scope.selectedArray.indexOf(id),1);
}
};
$scope.isSelected = function (id) {
if( $scope.selectedArray.indexOf(id) > -1){
return true;
}
return false;
};
}]);

Categories

Resources