Reputation: 179
I have an array of objects and each object has an email sender property like my sender{[email protected]}
. Now I want to fill a table with 2 values: 1) name ("my sender") and 2) address ("[email protected]").
Currently I use a filter to add the 2 new properties to my object and render it with an ng-repeat. My problem now is that I get an error
[$rootScope:infdig]
(but rendering result is fine). I googled a bit and the problem may be that I create a new array in my filter and the property length not match with the ng-repeat object length.
I am new to angularjs and I am not sure if I use the filter totally wrong and there is a much bether way for my wanted solution?
Demo Code JS:
demoApp.filter("customFilter", function () {
return function (input) {
var result = [];
if (input && input.length && input.length > 0) {
for (var i = 0; i < input.length; i++) {
var senderName = "";
var senderDomain = "";
var both = input[i].Name;
both = both.split("").reverse().join("");
senderName = both.substring(both.indexOf("<") + 1).split("").reverse().join("");
senderDomain = both.substring(1, both.indexOf("<")).split("").reverse().join("");
var domainBeforeAt = senderDomain.split("@")[0];
var domainAfterAt = senderDomain.split("@")[1];
var output = {
"customId": i,
"displayName": senderName,
"domain": {
"full": senderDomain,
"beforeAt": domainBeforeAt,
"afterAt": domainAfterAt,
}
}
result.push(output);
}
}
return result;
}
});
Demo Code HTML:
<div ng-repeat="sender in list.Sender | customFilter track by $index">
Upvotes: 0
Views: 820
Reputation: 1818
Update: In order to meet the requirement of accessing nested objects in the filter, I have changed the way the filter returns output.
.filter("customFilter", function () {
return function (input, params) {
...
var args = Array.prototype.slice.call(arguments);
var toReturn = output;
for (var i = 1; i < args.length; i++) {
toReturn = toReturn[args[i]];
}
return toReturn;
};
});
Without using eval, to return output.domain.full
, you'll have to pass in the levels of the nested object as parameters to the filter, e.g.:
<td class="col-xs-6">{{sender.Name | customFilter:'domain':'full'}}</td>
So, I think your issue stems from the fact that you want to track by $index in your ng-repeat, not in your filter. Once you have set up the ng-repeat
directive inside your div
, what you are passing into your filter is each individual sender in your data set, not all of them in an array, so you don't need to run a for loop over the input.
One approach, which I've done in the snippet below, is to pass what parameter you want to display (name, email) into the filter and get that property of the object your filter outputs. Another approach would be to create a separate name and email filter and apply them individually, but you'd be repeating a lot of code that way.
angular.module('demoApp', [])
.controller('SenderListCtrl', function() {
var ctrl = this;
ctrl.Sender = [
{
Name: "my sender<[email protected]>",
Age: 21
},
{
Name: "another sender<[email protected]>",
Age: 37
},
{
Name: "yet another sender<[email protected]>",
Age: 28
}
];
})
.filter("customFilter", function () {
return function (input, params) {
if (input && input.length && input.length > 0) {
var senderName = "";
var senderDomain = "";
var both = input;
senderName = both.substring(0, both.indexOf("<"));
senderDomain = both.substring(both.indexOf("<")+1,both.indexOf(">"));
var domainBeforeAt = senderDomain.split("@")[0];
var domainAfterAt = senderDomain.split("@")[1];
var output = {
name: senderName,
email: senderDomain,
domain: {
full: senderDomain,
beforeAt: domainBeforeAt,
afterAt: domainAfterAt,
}
};
var args = Array.prototype.slice.call(arguments);
var toReturn = output;
for (var i = 1; i < args.length; i++) {
toReturn = toReturn[args[i]];
}
return toReturn;
};
};
});
<!DOCTYPE html>
<html ng-app="demoApp">
<head>
<link data-require="[email protected]" data-semver="3.3.6" rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.css" />
<script data-require="[email protected]" data-semver="1.5.0" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0/angular.js"></script>
<script data-require="[email protected]" data-semver="3.3.6" src="bootstrap-js"></script>
<script src="script.js"></script>
</head>
<body ng-controller="SenderListCtrl as list">
<table>
<thead>
<tr>
<th class="col-xs-6">Name</th>
<th class="col-xs-6">Email</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="sender in list.Sender track by $index">
<td class="col-xs-6">{{sender.Name | customFilter:'name'}}</td>
<td class="col-xs-6">{{sender.Name | customFilter:'domain':'full'}}</td>
</tr>
</tbody>
</table>
</body>
</html>
Cheers!
Upvotes: 1