Building a simple app that filters results based on an input field. I'm adding a bunch of links that are outside of the repeated list and when clicked I want to be able to filter the list below.
I've searched online for various ways of tackling this problem but have yet to find a solution.
I'm already filtering by search, however I'd like to be able to click a link that is a popular search entry.
My code is:
tag one
tag two
tag three
<tr ng-repeat="item in items | orderBy:'date' | filter:itemsFilter" ng-click="clickedItem(item.id)">
<td><img ng-src="{{item.imageUrl}}" alt="{{item.title}}"></td>
<td>
{{item.title}}<br>
</td>
<td><i class="el el-time"></i> {d{item.date}}</td>
<td class="drop-me">{{item.description}}</td>
<td class="tag-me">{{item.tag}}</td>
</tr>
<tr ng-hide="item.length == 0"><td><p>There are no items!</p></td></tr>
I've tried custom filters, just can't figure a way to inject the items via an ng-click and update the list below.
I'd like to click one of the tag links and it filter the list below
Thanks
As proposed in the comments you can create an array to which you're adding your tags for filtering and in a custom filter you can filter your items array.
Also ngTagsInput is a nice directive that's helping to create a input field with tags.
Please have a look at the demo below or this jsfiddle.
angular.module('demoApp', ['ngTagsInput'])
// filter from here (with some modifications) http://stackoverflow.com/questions/23785592/apply-dynamic-filters-using-tags
.filter('filterByTags', function() {
return function(items, tags) {
var filtered = []; // Put here only items that match
(items || []).forEach(function(item) { // Check each item
var matches = tags.some(function(tag) { // If there is some tag
return item.tag == tag.text;
}); // we have a match
if (matches) { // If it matches
filtered.push(item); // put it into the `filtered` array
}
});
return filtered.length == 0 ? items : filtered; // Return the array with items that match any tag // return all if no tags
};
})
.controller('mainController', MainCtrl);
function MainCtrl() {
var vm = this;
function isTagInTags(tag) {
var seen = false;
//console.log('test', tag);
for (var i = 0; i < vm.tags.length; i++) {
//console.log(vm.tags[i].text, tag);
if (vm.tags[i].text == tag) {
seen = true;
return seen;
}
}
return seen;
}
vm.addTag = function(tag) {
//console.log(tag);
if (!isTagInTags(tag)) {
vm.tags.push({
text: tag
});
}
};
vm.data = [{
id: 0,
tag: 'JavaScript',
title: 'this is JS related'
}, {
id: 1,
tag: 'Java',
title: 'this is Java related'
}, {
id: 2,
tag: 'Python',
title: 'this is Python related'
}, {
id: 3,
tag: 'Python',
title: 'also Python stuff...'
}];
var unique = [];
vm.availTags = [];
for (i in vm.data) {
var item = vm.data[i];
//console.log(item);
if (unique.indexOf(item.tag) === -1) {
unique.push(item.tag);
vm.availTags.push(item.tag);
}
}
vm.loadItems = function(query) {
//console.log(query);
return vm.availTags.filter(function(tag) {
var testTag = tag.toLowerCase();
return testTag.indexOf(query.toLowerCase()) >= 0;
});
//return $http.get('/tags?query=' + query); // use this with a backend
}
//console.log(vm.availTags);
vm.tags = []; //vm.availTags[0];
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.7/angular.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/ng-tags-input/3.1.1/ng-tags-input.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/ng-tags-input/3.1.1/ng-tags-input.css" rel="stylesheet" />
<div ng-app="demoApp" ng-controller="mainController as ctrl">
<button ng-click="ctrl.addTag('JavaScript')">
JavaScript
</button>
<button ng-click="ctrl.addTag('Java')">
Java
</button>
<!--{{ctrl.tags}}-->
<tags-input ng-model="ctrl.tags">
<auto-complete source="ctrl.loadItems($query)"></auto-complete>
</tags-input>
<div ng-repeat="item in ctrl.data | filterByTags: ctrl.tags">
{{item.title}}
</div>
</div>
try addition ng-href
<a ng-href="">tag one</a>
<a ng-href="">tag two</a>
<a ng-href="">tag three</a>
<tr ng-repeat="item in items | orderBy:'date' | filter:itemsFilter" ng-click="clickedItem(item.id)">
<td><a ng-href="{{item.url}}"><img ng-src="{{item.imageUrl}}" alt="{{item.title}}"></a></td>
<td>
<a ng-href="{{item.url}}">{{item.title}}</a><br>
</td>
<td><i class="el el-time"></i> {d{item.date}}</td>
<td class="drop-me">{{item.description}}</td>
<td class="tag-me">{{item.tag}}</td>
</tr>
<tr ng-hide="item.length == 0"><td><p>There are no items!</p></td></tr>
I am aware that it may be Duplicate Question, but I tried that too but it didnt work it. So, I am posting my Question now. My Question is Apply the Date range filter using Angular js only one column.
Here is MY code:
HTML:
<div ng-app="myApp" ng-controller="myCtrl">
<div>
<table>
<tr>
<td>Start Date</td>
<td><input type="text" name="S_Date" ng-model="startDate"/></td>
<td>End Date</td>
<td><input type="text" name="E_Date" ng-model="endDate"/>
</tr>
</table>
</div>
<table>
<tr>
<th>Date</th>.
<th>Stock</th>
</tr>
<tr ng-repeat="subject in records |myfilter:startDate:endDate">
<td>{{ subject.name * 1000|date:'dd-MM-yyyy'}}<td>
<td>{{ subject.marks }}</td>
</tr>
</table>
Angular JS:
<script>
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.records = [
{
"name" : "2016-08-01",
"marks" : 250
},{
"name" : "2016-08-02",
"marks" : 150
},{
"name" : "2016-08-03",
"marks" : 100
},{
"name" : "2016-08-04",
"marks" : 150
},{
"name" : "2016-05-01",
"marks" : 750
},{
"name" : "2016-05-02",
"marks" : 1500
},{
"name" : "2016-03-03",
"marks" : 500
},{
"name" : "2016-04-04",
"marks" : 650
}
]
function parseDate(input) {
var parts = input.split('-');
return new Date(parts[2], parts[1]-1, parts[0]);
}
app.filter("myfilter", function() {
return function(items, from1, to) {
var df = parseDate(from1);
var dt = parseDate(to);
alert(df)
alert(dt)
var result = [];
for (var i=0; i<items.length; i++){
var tf = new Date(items[i].startDate * 1000),
tt = new Date(items[i].endDate * 1000);
if (tf > df && tt < dt) {
result.push(items[i]);
}
}
return result;
};
});
});
</script>
Please advice me Where I am going wrong.Please suggest me.Thanks in advance.
I recommend you to use moment.js library: http://momentjs.com/
Here is working plunkr with your range filter: https://plnkr.co/edit/dfpsBI0uom5ZAEnDF3wM?p=info
<div ng-controller="MainCtrl">
<table>
<tr>
<td>Start Date</td>
<td>
<input type="text" name="S_Date" ng-model="startDate" />
</td>
<td>End Date</td>
<td>
<input type="text" name="E_Date" ng-model="endDate" />
</td>
</tr>
</table>
<table>
<tr>
<th>Date</th>.
<th>Stock</th>
</tr>
<tr ng-repeat="subject in records | myfilter: startDate: endDate">
<td>{{ subject.name | date:'dd-MM-yyyy'}}</td>
<td>{{ subject.marks }}</td>
</tr>
</table>
</div>
app.controller('MainCtrl', function($scope) {
$scope.startDate = "2016-08-01";
$scope.endDate = "2016-08-03";
$scope.records = [{
"name": "2016-08-01",
"marks": 250
}, {
"name": "2016-08-02",
"marks": 150
}, {
"name": "2016-08-03",
"marks": 100
}, {
"name": "2016-08-04",
"marks": 150
}, {
"name": "2016-05-01",
"marks": 750
}, {
"name": "2016-05-02",
"marks": 1500
}, {
"name": "2016-03-03",
"marks": 500
}, {
"name": "2016-04-04",
"marks": 650
}];
});
app.filter("myfilter", function($filter) {
return function(items, from, to) {
return $filter('filter')(items, "name", function(v) {
var date = moment(v);
return date >= moment(from) && date <= moment(to);
});
};
});
$scope.Customfilterobj`enter code here` = { status: "Complete",StartDate: "2017-02-01T08:00:00",EndDate: "2018-02-01T08:00:00 " };
<tr ng-repeat="dt in data | filter: {Status: Customfilterobj.status} | dateRange:Customfilterobj.StartDate:Customfilterobj.EndDate">
Here we have use two filters as below:
filter: {Status: Customfilterobj.status} work as compare "complete" value with Status of data collection.
dateRange:Customfilterobj.StartScheuleDate:Customfilterobj.EndScheuleDate" : dateRange is custom filter for compare Expiration_date between StartDate and EndDate.
app.filter('dateRange', function () {
return function (data, greaterThan, lowerThan) {
if (greaterThan != null && lowerThan != null && greaterThan != undefined && lowerThan != undefined) {
data = data.filter(function (item) {
if (item.Expiration_date != null) {
var exDate = new Date(item.Expiration_date);
return exDate >= new Date(greaterThan) && exDate <= new Date(lowerThan);
}
});
}
return data;
};
});
Adding off of Roman Koliada's plunker. His process has a small issue in the usage of the angular $filter. I have the updated here:
https://plnkr.co/edit/l4t4Fln4HhmZupbmOFki?p=preview
New filter:
app.filter("myfilter", function($filter) {
return function(items, from, to, dateField) {
startDate = moment(from);
endDate = moment(to);
return $filter('filter')(items, function(elem) {
var date = moment(elem[dateField]);
return date >= startDate && date <= endDate;
});
};
});
The issue was that the function input into $filter function was the third param, and loops over every attribute of every object in the list. Console logging his plunker calls moment() on every single attribute of every object. By instead inputting a function as the second param, as the expression instead of the comparator - we can call the comparison only on the date field.
Angular doc: https://docs.angularjs.org/api/ng/filter/filter
I want to use the filter in angular and want to filter for multiple values, if it has either one of the values then it should be displayed.
I have for example this structure:
An object movie which has the property genres and I want to filter for Action and Comedy.
I know I can do filter:({genres: 'Action'} || {genres: 'Comedy'}), but what to do if I want to filter it dynamically. E.g. filter: variableX
How do I set variableX in the $scope, when I have an array of the genres I have to filter?
I could construct it as a string and then do an eval() but I don't want to use eval()...
I would just create a custom filter. They are not that hard.
angular.module('myFilters', []).
filter('bygenre', function() {
return function(movies,genres) {
var out = [];
// Filter logic here, adding matches to the out var.
return out;
}
});
template:
<h1>Movies</h1>
<div ng-init="movies = [
{title:'Man on the Moon', genre:'action'},
{title:'Meet the Robinsons', genre:'family'},
{title:'Sphere', genre:'action'}
];" />
<input type="checkbox" ng-model="genrefilters.action" />Action
<br />
<input type="checkbox" ng-model="genrefilters.family" />Family
<br />{{genrefilters.action}}::{{genrefilters.family}}
<ul>
<li ng-repeat="movie in movies | bygenre:genrefilters">{{movie.title}}: {{movie.genre}}</li>
</ul>
Edit here is the link: Creating Angular Filters
UPDATE: Here is a fiddle that has an exact demo of my suggestion.
You can use a controller function to filter.
function MoviesCtrl($scope) {
$scope.movies = [{name:'Shrek', genre:'Comedy'},
{name:'Die Hard', genre:'Action'},
{name:'The Godfather', genre:'Drama'}];
$scope.selectedGenres = ['Action','Drama'];
$scope.filterByGenres = function(movie) {
return ($scope.selectedGenres.indexOf(movie.genre) !== -1);
};
}
HTML:
<div ng-controller="MoviesCtrl">
<ul>
<li ng-repeat="movie in movies | filter:filterByGenres">
{{ movie.name }} {{ movie.genre }}
</li>
</ul>
</div>
Creating a custom filter might be overkill here, you can just pass in a custom comparator, if you have the multiples values like:
$scope.selectedGenres = "Action, Drama";
$scope.containsComparator = function(expected, actual){
return actual.indexOf(expected) > -1;
};
then in the filter:
filter:{name:selectedGenres}:containsComparator
Here is the implementation of custom filter, which will filter the data using array of values.It will support multiple key object with both array and single value of keys. As mentioned inangularJS API AngularJS filter Doc supports multiple key filter with single value, but below custom filter will support same feature as angularJS and also supports array of values and combination of both array and single value of keys.Please find the code snippet below,
myApp.filter('filterMultiple',['$filter',function ($filter) {
return function (items, keyObj) {
var filterObj = {
data:items,
filteredData:[],
applyFilter : function(obj,key){
var fData = [];
if (this.filteredData.length == 0)
this.filteredData = this.data;
if (obj){
var fObj = {};
if (!angular.isArray(obj)){
fObj[key] = obj;
fData = fData.concat($filter('filter')(this.filteredData,fObj));
} else if (angular.isArray(obj)){
if (obj.length > 0){
for (var i=0;i<obj.length;i++){
if (angular.isDefined(obj[i])){
fObj[key] = obj[i];
fData = fData.concat($filter('filter')(this.filteredData,fObj));
}
}
}
}
if (fData.length > 0){
this.filteredData = fData;
}
}
}
};
if (keyObj){
angular.forEach(keyObj,function(obj,key){
filterObj.applyFilter(obj,key);
});
}
return filterObj.filteredData;
}
}]);
Usage:
arrayOfObjectswithKeys | filterMultiple:{key1:['value1','value2','value3',...etc],key2:'value4',key3:[value5,value6,...etc]}
Here is a fiddle example with implementation of above "filterMutiple" custom filter.
:::Fiddle Example:::
If you want to filter on Array of Objects then you can give
filter:({genres: 'Action', key :value }.
Individual property will be filtered by particular filter given for that property.
But if you wanted to something like filter by individual Property and filter globally for all properties then you can do something like this.
<tr ng-repeat="supp in $data | filter : filterObject | filter : search">
Where "filterObject" is an object for searching an individual property and "Search" will search in every property globally.
~Atul
I've spent some time on it and thanks to #chrismarx, I saw that angular's default filterFilter allows you to pass your own comparator. Here's the edited comparator for multiple values:
function hasCustomToString(obj) {
return angular.isFunction(obj.toString) && obj.toString !== Object.prototype.toString;
}
var comparator = function (actual, expected) {
if (angular.isUndefined(actual)) {
// No substring matching against `undefined`
return false;
}
if ((actual === null) || (expected === null)) {
// No substring matching against `null`; only match against `null`
return actual === expected;
}
// I edited this to check if not array
if ((angular.isObject(expected) && !angular.isArray(expected)) || (angular.isObject(actual) && !hasCustomToString(actual))) {
// Should not compare primitives against objects, unless they have custom `toString` method
return false;
}
// This is where magic happens
actual = angular.lowercase('' + actual);
if (angular.isArray(expected)) {
var match = false;
expected.forEach(function (e) {
e = angular.lowercase('' + e);
if (actual.indexOf(e) !== -1) {
match = true;
}
});
return match;
} else {
expected = angular.lowercase('' + expected);
return actual.indexOf(expected) !== -1;
}
};
And if we want to make a custom filter for DRY:
angular.module('myApp')
.filter('filterWithOr', function ($filter) {
var comparator = function (actual, expected) {
if (angular.isUndefined(actual)) {
// No substring matching against `undefined`
return false;
}
if ((actual === null) || (expected === null)) {
// No substring matching against `null`; only match against `null`
return actual === expected;
}
if ((angular.isObject(expected) && !angular.isArray(expected)) || (angular.isObject(actual) && !hasCustomToString(actual))) {
// Should not compare primitives against objects, unless they have custom `toString` method
return false;
}
console.log('ACTUAL EXPECTED')
console.log(actual)
console.log(expected)
actual = angular.lowercase('' + actual);
if (angular.isArray(expected)) {
var match = false;
expected.forEach(function (e) {
console.log('forEach')
console.log(e)
e = angular.lowercase('' + e);
if (actual.indexOf(e) !== -1) {
match = true;
}
});
return match;
} else {
expected = angular.lowercase('' + expected);
return actual.indexOf(expected) !== -1;
}
};
return function (array, expression) {
return $filter('filter')(array, expression, comparator);
};
});
And then we can use it anywhere we want:
$scope.list=[
{name:'Jack Bauer'},
{name:'Chuck Norris'},
{name:'Superman'},
{name:'Batman'},
{name:'Spiderman'},
{name:'Hulk'}
];
<ul>
<li ng-repeat="item in list | filterWithOr:{name:['Jack','Chuck']}">
{{item.name}}
</li>
</ul>
Finally here's a plunkr.
Note: Expected array should only contain simple objects like String, Number etc.
you can use searchField filter of angular.filter
JS:
$scope.users = [
{ first_name: 'Sharon', last_name: 'Melendez' },
{ first_name: 'Edmundo', last_name: 'Hepler' },
{ first_name: 'Marsha', last_name: 'Letourneau' }
];
HTML:
<input ng-model="search" placeholder="search by full name"/>
<th ng-repeat="user in users | searchField: 'first_name': 'last_name' | filter: search">
{{ user.first_name }} {{ user.last_name }}
</th>
<!-- so now you can search by full name -->
You can also use ngIf if the situation permits:
<div ng-repeat="p in [
{ name: 'Justin' },
{ name: 'Jimi' },
{ name: 'Bob' }
]" ng-if="['Jimi', 'Bob'].indexOf(e.name) > -1">
{{ p.name }} is cool
</div>
The quickest solution that I've found is to use the filterBy filter from angular-filter, for example:
<input type="text" placeholder="Search by name or genre" ng-model="ctrl.search"/>
<ul>
<li ng-repeat="movie in ctrl.movies | filterBy: ['name', 'genre']: ctrl.search">
{{movie.name}} ({{movie.genre}}) - {{movie.rating}}
</li>
</ul>
The upside is that angular-filter is a fairly popular library (~2.6k stars on GitHub) which is still actively developed and maintained, so it should be fine to add it to your project as a dependency.
I believe this is what you're looking for:
<div>{{ (collection | fitler1:args) + (collection | filter2:args) }}</div>
Please try this
var m = angular.module('yourModuleName');
m.filter('advancefilter', ['$filter', function($filter){
return function(data, text){
var textArr = text.split(' ');
angular.forEach(textArr, function(test){
if(test){
data = $filter('filter')(data, test);
}
});
return data;
}
}]);
Lets assume you have two array, one for movie and one for genre
Just use the filter as: filter:{genres: genres.type}
Here genres being the array and type has value for genre
I wrote this for strings AND functionality (I know it's not the question but I searched for it and got here), maybe it can be expanded.
String.prototype.contains = function(str) {
return this.indexOf(str) != -1;
};
String.prototype.containsAll = function(strArray) {
for (var i = 0; i < strArray.length; i++) {
if (!this.contains(strArray[i])) {
return false;
}
}
return true;
}
app.filter('filterMultiple', function() {
return function(items, filterDict) {
return items.filter(function(item) {
for (filterKey in filterDict) {
if (filterDict[filterKey] instanceof Array) {
if (!item[filterKey].containsAll(filterDict[filterKey])) {
return false;
}
} else {
if (!item[filterKey].contains(filterDict[filterKey])) {
return false;
}
}
}
return true;
});
};
});
Usage:
<li ng-repeat="x in array | filterMultiple:{key1: value1, key2:[value21, value22]}">{{x.name}}</li>
Angular Or Filter Module
$filter('orFilter')([{..}, {..} ...], {arg1, arg2, ...}, false)
here is the link: https://github.com/webyonet/angular-or-filter
I had similar situation. Writing custom filter worked for me. Hope this helps!
JS:
App.filter('searchMovies', function() {
return function (items, letter) {
var resulsts = [];
var itemMatch = new RegExp(letter, 'i');
for (var i = 0; i < items.length; i++) {
var item = items[i];
if ( itemMatch.test(item.name) || itemMatch.test(item.genre)) {
results.push(item);
}
}
return results;
};
});
HTML:
<div ng-controller="MoviesCtrl">
<ul>
<li ng-repeat="movie in movies | searchMovies:filterByGenres">
{{ movie.name }} {{ movie.genre }}
</li>
</ul>
</div>
Here is my example how create filter and directive for table jsfiddle
directive get list (datas) and create table with filters
<div ng-app="autoDrops" ng-controller="HomeController">
<div class="row">
<div class="col-md-12">
<h1>{{title}}</h1>
<ng-Multiselect array-List="datas"></ng-Multiselect>
</div>
</div>
</div>
my pleasure if i help you
Too late to join the party but may be it can help someone:
We can do it in two step, first filter by first property and then concatenate by second filter:
$scope.filterd = $filter('filter')($scope.empList, { dept: "account" });
$scope.filterd = $scope.filterd.concat($filter('filter')($scope.empList, { dept: "sales" }));
See the working fiddle with multiple property filter
OPTION 1:
Using Angular providered filter comparator parameter
// declaring a comparator method
$scope.filterBy = function(actual, expected) {
return _.contains(expected, actual); // uses underscore library contains method
};
var employees = [{name: 'a'}, {name: 'b'}, {name: 'c'}, {name: 'd'}];
// filter employees with name matching with either 'a' or 'c'
var filteredEmployees = $filter('filter')(employees, {name: ['a','c']}, $scope.filterBy);
OPTION 2:
Using Angular providered filter negation
var employees = [{name: 'a'}, {name: 'b'}, {name: 'c'}, {name: 'd'}];
// filter employees with name matching with either 'a' or 'c'
var filteredEmployees = $filter('filter')($filter('filter')(employees, {name: '!d'}), {name: '!b'});
My solution
ng-repeat="movie in movies | filter: {'Action'} + filter: {'Comedy}"
the best answer is :
filter:({genres: 'Action', genres: 'Comedy'}
I have following JSON:
[{
"Id": "1",
"Data": {"Str1": "Ann", "Str2": "Xenna"}
},{
"Id": "2",
"Data": {"Str1": "Bob","Str2": "Bobby"},
}]
And I created ng-table to display it. I tried to add filter. When I filter by Id everything works as expected (filter is { "Id": "2" }). But I cannot create proper filter do Str1 and Str2 fields. I already tried:
{ "Str1": "A" }
{ "Data.Str1": "A" }
{ "Data['Str1']": "A" }
but above options does not work.
Example of my work is here: http://plnkr.co/edit/MyJCqTlgvKLtSP63FYQY?p=preview
Update
Thanks to #Blackhole I founded that filter {Data: {Str1: 'A'}} works. But I can only delcare this in code. When I try to put something like this in HTML it doesn't even show filter:
<td data-title="'Str1'" filter="{Data:{Str1: 'text'}}">
{{ user.Data.Str1 }}
</td>
When you try to use filter="{Data:{Str1: 'text'}}" in html,input doesn't showing cause of template in header,have a look in source code.
<div ng-repeat="(name, filter) in column.filter"> //!!!! right here it's not supported
<div ng-if="column.filterTemplateURL" ng-show="column.filterTemplateURL">
<div ng-include="column.filterTemplateURL"></div>
</div>
<div ng-if="!column.filterTemplateURL" ng-show="!column.filterTemplateURL">
<div ng-include="'ng-table/filters/' + filter + '.html'"></div>
</div>
</div>
right here <div ng-repeat="(name, filter) in column.filter"> it's not dig into nested objects
Ngtable not support nested filter in default template,so you can create your own template,which gonna support it.Have a look to example of header template.
Note
This how column.filter is initializing,it's parsing from filter attribute on td tag,source
var parsedAttribute = function (attr, defaultValue) {
return function (scope) {
return $parse(el.attr('x-data-' + attr) ||
el.attr('data-' + attr) ||
el.attr(attr))
(scope, {
$columns: columns
}) || defaultValue;
};
};
var parsedTitle = parsedAttribute('title', ' '),
headerTemplateURL = parsedAttribute('header', false),
// here
filter = parsedAttribute('filter', false)(),
filterTemplateURL = false,
filterName = false;
...
columns.push({
....
filter: filter,
Doing a loop within a loop in a view:
<tr ng-repeat="result in results">
<td>
<span ng-repeat="device in helpers.getIosDevices(result.ios_device)">
{{ device.code }}
</span>
</td>
</tr>
The controller:
$scope.helpers = CRM.helpers;
The helper:
var CRM = CRM || {};
CRM.helpers = {
// Handle "111" value format
getIosDevices: function (devices) {
var obj = [];
if (devices !== null && devices !== undefined) {
if (devices.charAt(0) === '1') {
obj.push({
code: 'ipod',
name: 'iPod',
});
}
if (devices.charAt(1) === '1') {
obj.push({
code: 'ipad',
name: 'iPad',
});
}
if (devices.charAt(2) === '1') {
obj.push({
code: 'iphone',
name: 'iPhone',
});
}
}
return obj;
}
};
Got this error: https://docs.angularjs.org/error/$rootScope/infdig?p0=10&p1=%5B%5B%22fn:%E2%80%A620%20%20%7D;%20newVal:%20undefined;%20oldVal:%20undefined%22%5D%5D
as I understand but I don't know how can I solve it in my case. What workaround should I use?
The reason of this error that you try to change source list in ng-repeat directive during digest cycle.
<span ng-repeat="device in helpers.getIosDevices(result.ios_device)">
^^^^^^^^
and obj.push(/* ... */) in getIosDevices
First we need ask our self when digest cycle will stop looping: It will stop when Angular detect that on several iterations the list didn't change. In your case each time when ng-repeat calls getIosDevices method - the list gets different items and therefore it looping again till you get limit and Angular drops this exception.
So what is a solution:
In Angular its not good practice to call method getList() in ngRepeat. Because developpers make bugs.
Its clear that in your case getIosDevices() list depends on results therefore I would create different fixed object with some watcher on results and write HTML part like:
<tr ng-repeat="result in results">
<td>
<span ng-repeat="device in devices[result.ios_device]">
{{ device.code }}
</span>
</td>
</tr>
where devices represents Map.
This is some demo that might help you:
$scope.results = [{
ios_device: "100"
}, {
ios_device: "010"
}, {
ios_device: "001"
}];
$scope.devices = {
"100": [{
code: 'ipod',
name: 'iPod1',
},
{
code: 'ipod',
name: 'iPod2',
}],
"010": [{
code: 'ipod',
name: 'iPod1',
},
{
code: 'ipad',
name: 'iPad2',
}],
"001": [{
code: 'ipod',
name: 'iPod1',
},
{
code: 'iphone',
name: 'iphone2',
}],
}
HTML
<table>
<tr ng-repeat="result in results">
<td><span ng-repeat="device in devices[result.ios_device]">
{{ device.code }}
</span>
</td>
</tr>
</table>
Demo in Fiddle