I'm trying to understand the concept of custom filter in AngularJS. Therefor I've made a simple table which I want to filter. I know I can do the filtering simple with the built-in Angular filter, but I made this for exercise purpose. I know the filter is not completed yet. It doesn't return anything. First I want to solve the following:
I'm having a problem with adding an object to an array. It should be simple with array.push(object). But in the 'for loop' the previous object is being replaced by the new one. I don't know why that is happening. To investigate this problem I've added a few console.log's to see (and hopefully understand) what is happening. But I cannot figure it out.
There's is also another behavior I cannot explain: the loop is running twice: it goes through the same array (vm.players) a second time. Does anyone has an explanation for this behavior?
This is my angularJS script:
var app = angular.module('main', ['angular.filter'])
.filter('filterIns', function() {
return function(input, ins) {
var out = [];
var obj = {};
for (var i = 0; i < input.length; i++) {
if (input[i].instrument == ins) {
obj.name = input[i].name;
obj.instrument = input[i].instrument;
console.log(obj);
out.push(obj);
console.log('inside IF ' + i);
console.log(out);
}
}
}
})
.controller('DemoCtrl', function() {
var vm = this;
vm.players = [
{
"name": "Mariko",
"instrument": "horn"
}, {
"name": "Kareem",
"instrument": "cello"
}, {
"name": "Lance",
"instrument": "horn"
}, {
"name": "Gail",
"instrument": "flute"
}, {
"name": "Armand",
"instrument": "cello"
}, {
"name": "Anika",
"instrument": "flute"
}, {
"name": "Mallory",
"instrument": "clarinet"
}, {
"name": "Odysseus",
"instrument": "clarinet"
}, {
"name": "Colt",
"instrument": "cello"
}, {
"name": "Kessie",
"instrument": "violin"
}, {
"name": "Iola",
"instrument": "horn"
}
];
});
And the html:
<!DOCTYPE html>
<html>
<head>
<script data-require="[email protected]" data-semver="1.6.5" src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.5/angular.min.js"></script>
<script data-require="[email protected]" data-semver="0.5.7" src="//cdnjs.cloudflare.com/ajax/libs/angular-filter/0.5.7/angular-filter.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body ng-app="main">
<div ng-controller="DemoCtrl as demo">
<div>
<table border="0">
<tr>
<th>name</th>
<th>instrument</th>
</tr>
<tr ng-repeat="nr in demo.players | filterIns:'flute' ">
<td>{{nr.name }}</td>
<td>{{nr.instrument}}</td>
</tr>
</table>
</div>
</div>
</body>
</html>
Please have a look at this plunk
-
Have a look plnkr.co/edit/ZGOnEblMJudBRWkKi8u1?p=previewUshma Joshi– Ushma Joshi2017年10月10日 11:58:43 +00:00Commented Oct 10, 2017 at 11:58
-
@UshmaJoshi: That did the trick: creating an empty object before the return function. Also a good point to add the object as a whole and not per key/value pair as I did in my first plunk. But still I have this question: why is the return function running a second time? I don't understand this behavior.Jojoseph– Jojoseph2017年10月11日 07:34:06 +00:00Commented Oct 11, 2017 at 7:34
3 Answers 3
Objects are references in javascript, as in other programming languages. Modifying anything in an object will affect all references that points to the same object.
So:
var obj = {a:1};
var obj1 = obj;
obj.a = 2;
console.log(obj1.a); // 2
To fix your issue, you'll need to create a new object in each loop
for (var i = 0; i < input.length; i++) {
var obj = {a:xx, b:yy};
// don't use obj.a = xx; obj.b = yy;
out.push(obj);
}
1 Comment
Array override previous value: It is because you are creating an object 'obj' outside of for loop. Please, create object inside the for loop in filter.
so filter code is like below:
.filter('filterIns', function(){
return function(input, ins) {
console.log(ins);
var out = [];
for (var i = 0; i < input.length; i++)
if (input[i].instrument == ins) {
var obj ={};
obj.name = input[i].name;
obj.instrument = input[i].instrument;
out.push(obj);
}
}
console.log(out);
}
})
Comments
This is normal, angularjs uses a 'dirty-check' approach, so it needs to call all the filters to see if any changes exist. After this it detects that you have a change on one variable (the one that you typed) and then it re-executes all filters again to detect if it has other changes. This is the edited plunker for your object replaced issue.
.filter('filterIns', function(){
return function(input, ins) {
var obj ={};
var out = [];
for (var i = 0; i < input.length; i++) {
if (input[i].instrument == ins) {
obj = input[i];
out.push(obj);
}
console.log(out);
}
}