Error: [ngRepeat:dupes] on a seemingly valid object [duplicate] - angularjs

I am defining a custom filter like so:
<div class="idea item" ng-repeat="item in items" isoatom>
<div class="section comment clearfix" ng-repeat="comment in item.comments | range:1:2">
....
</div>
</div>
As you can see the ng-repeat where the filter is being used is nested within another ng-repeat
The filter is defined like this:
myapp.filter('range', function() {
return function(input, min, max) {
min = parseInt(min); //Make string input int
max = parseInt(max);
for (var i=min; i<max; i++)
input.push(i);
return input;
};
});
I'm getting:
Error: Duplicates in a repeater are not allowed. Repeater: comment in item.comments | range:1:2 ngRepeatAction#https://ajax.googleapis.com/ajax/libs/angularjs/1.1.4/an

The solution is actually described here: http://www.anujgakhar.com/2013/06/15/duplicates-in-a-repeater-are-not-allowed-in-angularjs/
AngularJS does not allow duplicates in a ng-repeat directive. This means if you are trying to do the following, you will get an error.
// This code throws the error "Duplicates in a repeater are not allowed.
// Repeater: row in [1,1,1] key: number:1"
<div ng-repeat="row in [1,1,1]">
However, changing the above code slightly to define an index to determine uniqueness as below will get it working again.
// This will work
<div ng-repeat="row in [1,1,1] track by $index">
Official docs are here: https://docs.angularjs.org/error/ngRepeat/dupes

For those who expect JSON and still getting the same error, make sure that you parse your data:
$scope.customers = JSON.parse(data)

I was having an issue in my project where I was using ng-repeat track by $index but the products were not getting reflecting when data comes from database. My code is as below:
<div ng-repeat="product in productList.productList track by $index">
<product info="product"></product>
</div>
In the above code, product is a separate directive to display the product.But i came to know that $index causes issue when we pass data out from the scope. So the data losses and DOM can not be updated.
I found the solution by using product.id as a key in ng-repeat like below:
<div ng-repeat="product in productList.productList track by product.id">
<product info="product"></product>
</div>
But the above code again fails and throws the below error when more than one product comes with same id:
angular.js:11706 Error: [ngRepeat:dupes] Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater
So finally i solved the problem by making dynamic unique key of ng-repeat like below:
<div ng-repeat="product in productList.productList track by (product.id + $index)">
<product info="product"></product>
</div>
This solved my problem and hope this will help you in future.

What do you intend your "range" filter to do?
Here's a working sample of what I think you're trying to do: http://jsfiddle.net/evictor/hz4Ep/
HTML:
<div ng-app="manyminds" ng-controller="MainCtrl">
<div class="idea item" ng-repeat="item in items" isoatom>
Item {{$index}}
<div class="section comment clearfix" ng-repeat="comment in item.comments | range:1:2">
Comment {{$index}}
{{comment}}
</div>
</div>
</div>
JS:
angular.module('manyminds', [], function() {}).filter('range', function() {
return function(input, min, max) {
var range = [];
min = parseInt(min); //Make string input int
max = parseInt(max);
for (var i=min; i<=max; i++)
input[i] && range.push(input[i]);
return range;
};
});
function MainCtrl($scope)
{
$scope.items = [
{
comments: [
'comment 0 in item 0',
'comment 1 in item 0'
]
},
{
comments: [
'comment 0 in item 1',
'comment 1 in item 1',
'comment 2 in item 1',
'comment 3 in item 1'
]
}
];
}

If by chance this error happens when working with SharePoint 2010: Rename your .json file extensions and be sure to update your restService path. No additional "track by $index" was required.
Luckily I was forwarded this link to this rationale:
.json becomes an important file type in SP2010. SP2010 includes certains webservice endpoints. The location of these files is 14hive\isapi folder. The extension of these files are .json. That is the reason it gives such a error.
"cares only that the contents of a json file is json - not its file extension"
Once the file extensions are changed, should be all set.

Just in case this happens to someone else, I'm documenting this here, I was getting this error because I mistakenly set the ng-model the same as the ng-repeat array:
<select ng-model="list_views">
<option ng-selected="{{view == config.list_view}}"
ng-repeat="view in list_views"
value="{{view}}">
{{view}}
</option>
</select>
Instead of:
<select ng-model="config.list_view">
<option ng-selected="{{view == config.list_view}}"
ng-repeat="view in list_views"
value="{{view}}">
{{view}}
</option>
</select>
I checked the array and didn't have any duplicates, just double check your variables.

Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys.
Repeater: {0}, Duplicate key: {1}, Duplicate value: {2}
Example
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8" />
<title></title>
<script src="angular.js"></script>
</head>
<body>
<div ng-app="myApp" ng-controller="personController">
<table>
<tr> <th>First Name</th> <th>Last Name</th> </tr>
<tr ng-repeat="person in people track by $index">
<td>{{person.firstName}}</td>
<td>{{person.lastName}}</td>
<td><input type="button" value="Select" ng-click="showDetails($index)" /></td>
</tr>
</table> <hr />
<table>
<tr ng-repeat="person1 in items track by $index">
<td>{{person1.firstName}}</td>
<td>{{person1.lastName}}</td>
</tr>
</table>
<span> {{sayHello()}}</span>
</div>
<script> var myApp = angular.module("myApp", []);
myApp.controller("personController", ['$scope', function ($scope)
{
$scope.people = [{ firstName: "F1", lastName: "L1" },
{ firstName: "F2", lastName: "L2" },
{ firstName: "F3", lastName: "L3" },
{ firstName: "F4", lastName: "L4" },
{ firstName: "F5", lastName: "L5" }]
$scope.items = [];
$scope.selectedPerson = $scope.people[0];
$scope.showDetails = function (ind)
{
$scope.selectedPerson = $scope.people[ind];
$scope.items.push($scope.selectedPerson);
}
$scope.sayHello = function ()
{
return $scope.items.firstName;
}
}]) </script>
</body>
</html>

If you call a ng-repeat within a < ul> tag, you may be able to allow duplicates. See this link for reference.
See Todo2.html

Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater: sdetail in mydt, Duplicate key: string: , Duplicate value:
I faced this error because i had written wrong database name in my php api part......
So this error may also occurs when you are fetching the data from database base, whose name is written incorrect by you.

My JSON response was like this:
{
"items": [
{
"index": 1, "name": "Samantha", "rarity": "Scarborough","email": "maureen#sykes.mk"
},{
"index": 2, "name": "Amanda", "rarity": "Vick", "email": "jessica#livingston.mv"
}
]
}
So, I used ng-repeat = "item in variables.items" to display it.

Related

Construct json from dynamic key and values in angularjs

i am developing a web application where am creating textboxes dynamically using the attributes from server. I am successfull in displaying the attribute values as html table inside modal. I need to create json object using the attributes in controller and make two way binding using angularjs. I am very new to angularjs.I need a json using the key and values like
{"NAME": "",
"TYPE: "forest"} and make two way binding for this dynamically created textboxes.
<tr ng-repeat="(key, value) in prop['properties']">
<td ><label>{{ key}}</label></td>
<td><input type="text" ng-value="value"></td>
</tr>
Just put ng-model in your input text element and bind the value to it
html
<table>
<tr ng-repeat="(key,value) in prop">
<td ><label>{{key}}</label></td>
<td><input type="text" ng-model="prop[key]"></td>
</tr>
</table>
<div>
{{prop | json}}
</div>
in controller
$scope.prop = {"NAME": "", "TYPE": "forest"} ;
demo codepen
Use ng-modal for two way binding.
HTML:
<div ng-repeat="item in items">
<input ng-model="item.value" type="text" size="40">
</div>
JavaScript:
app.controller('MainCtrl', function($scope) {
$scope.items = [
{value:'First Item'},
{value: 'Second Item'}
];
$scope.addInputItem = function() {
$scope.items.push({value:''});
};
});
Working code here: http://plnkr.co/edit/KIR7AyoF553STjOx
<div ng-app="myApp" ng-controller="controller">
Name: <input ng-model="details.name">
</div>
<script>
var app = angular.module('myApp', []);
app.controller('controller', function($scope) {
$scope.details = {};
$scope.details.name = "John Doe";
});
</script>
This might i think you were asking for

Iterating over JSON properties

I have successfully used the $http service in angular to pull a JSON object from another server using their API. I was able to then display the values like so...
<div ng-controller="ApiController as ApiCtrl">
{{ApiCtrl.Api.status}}
{{ApiCtrl.Api.meta.count}}
{{ApiCtrl.Api.data[0].nickname}}
{{ApiCtrl.Api.data[0].account_id}}
</div>
This displays the values correctly but I am unable to display the Keys. I read around, here and here. They explained that there is an ng-repeat that is set up to iterate through an object and pull the keys and values from it.
<div ng-controller="ApiController as ApiCtrl">
<div>
<div ng-repeat="(key, value) in Api">
{{key}} : {{value}}
</div>
</div>
</div>
For reference this is the ApiController
function ApiController($http) {
var vm = this;
vm.Api = [];
$http.get('...').success(function (data) {
vm.Api = data;
});
};
This is the Json that I requested
{
"status": "ok",
"meta": {
"count": 1
},
"data": [
{
"nickname": "Mitcha47",
"account_id": 1001356515
}
]
}
The second method ng-repeat="(key, value) in Api" does not work and only shows * ngRepeat: (key, value) in Api * in the html
Im quite confused about why it doesn't work and am not sure if its an incorrect use of syntax or from not understanding how the ng-repeat fully works.
Edit
After changing to div ng-repeat="(key,value) in ApiCtrl.Api" This was produced ->
status : ok
meta : {"count":1}
data : [{"nickname":"Mitcha47","account_id":1001356515}]'
Which is okay, but not exactly the format to put into a table, which is the next step. Would this be fixed by using the .fromJson function?
Do i include the ApiCtrl because multiple controllers can be used in each module and thus this keeps everything pointing to the correct values?
You need to specify the controller in your ng-repeat.
EDIT
According to the docs, when you use the controller as declaration methods and properties are bound directly to the controller instead of using $scope hence why you need to specify the controller because the Api object is a property of that controller.
I've changed the snippet to show the data in a table but I am unsure exactly what you want to display. Could you please provide an example?
<div ng-repeat="(key, value) in ApiCtrl.Api">
angular.module("app", [])
.controller("ApiController", ApiController);
function ApiController($http) {
var vm = this;
vm.Api = {
status: "good",
meta: {
count: 42
},
data: [{
nickname: "Timmy",
account_id: 1
}, {
nickname: "Johnny",
account_id: 2
}]
};
};
table {
border-collapse: collapse;
}
th,
td {
border: 1px solid black;
padding: 5px;
}
th {
text-align: left;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0/angular.min.js"></script>
<div ng-app="app">
<div ng-controller="ApiController as ApiCtrl">
{{ApiCtrl.Api.status}} {{ApiCtrl.Api.meta.count}} {{ApiCtrl.Api.data[0].nickname}} {{ApiCtrl.Api.data[0].account_id}}
</div>
<hr>
<div ng-controller="ApiController as ApiCtrl">
<div>
<table>
<thead>
<tr>
<th ng-repeat="(key, value) in ApiCtrl.Api">{{key}}</th>
</tr>
</thead>
<tbody>
<td ng-repeat="(key, value) in ApiCtrl.Api">
{{value}}
</td>
</tbody>
</table>
</div>
</div>
</div>
Possible problem can be here:
It should be -
<div ng-repeat="(key, value) in ApiCtrl.Api">
{{key}} : {{value}}
</div>
Instead of -
<div ng-repeat="(key, value) in Api">
{{key}} : {{value}}
</div>
If you use the controller as syntax, you have to use
ng-repeat="(key, value) in ApiCtrl.Api"

Can I get the value from the key from ng-repeat x in xx | unique x.key

I have a collection of items that represent a grouping by one property. I want to create a list of items grouped by the value of this property and in each list present the value of this group once and then all the items that belong to the group.
Something like the following
<div ng-repeat="items in itemcollection | unique: 'groupkey'">
<h3>{{items.groupkey}}</h3>
<div ng-repeat="item in items">
<label>{{item.name}}</label>
</div>
</div>
So if I have a itemscollection like the following:
{{ groupkey: 1; name: 'Ada'}, { groupkey: 1; name: 'Beda'}, {groupkey: 2; name: 'Ceda'}}
So after the generation of divs and labels the result should be
<div>
<h3>1</h3>
<div><label>Ada</label></div>
<div><label>Beda</label></div>
</div>
<div>
<h3>2</h3>
<div><label>Ceda</label></div>
</div>
Is it possible to create this or do I need to handle the creating of the elements to better construct the data to make this happen?
This filter does what you want : https://github.com/a8m/angular-filter#groupby
Yes. Its possible by the combination of orderBy and filter function in angularJS. The following code will work :
var app = angular.module("myApp", []);
app.controller("lists", function($scope) {
$scope.list = [{
groupkey: 1,
name: 'Ada'
}, {
groupkey: 1,
name: 'Beda'
}, {
groupkey: 2,
name: 'Ceda'
}];
});
<!DOCTYPE html>
<html lang="en" ng-app="myApp">
<head>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.18/angular.js"></script>
</head>
<body>
<div ng-controller="lists">
<div ng-repeat="items in list | orderBy:'groupkey'">
<h3>{{items.groupkey}}</h3>
<label>{{items.name}}</label>
</div>
</div>
</body>
</html>
Hope it works for you :)
Not tested but something like this I guess should work
<div ng-repeat="items in itemcollection | unique: 'groupkey'">
<h3>{{items.groupkey}}</h3>
<div ng-repeat="item in items | filter:{'groupkey': items.groupkey}:true">
<label>{{item.name}}</label>
</div>
</div>
If you make sure the itemcollection is sorted by groupkey you may display the groupkey header only when the groupkey differs from the previous groupkey. Then you achieve to only show the groupkey header once per group. Here is an example:
angular.module('myapp',[]).controller("thectrl", function($scope) {
$scope.itemcollection = [{ groupkey: 1, name: 'Ada'},
{ groupkey: 1, name: 'Beda'},
{groupkey: 2, name: 'Ceda'},
{groupkey: 2, name: 'D'}];
$scope.itemcollection.sort(function(a,b) { return a.groupkey-b.groupkey;});
});
The HTML:
<div ng-app="myapp" ng-controller="thectrl">
<div ng-repeat="item in itemcollection track by $index" >
<h3 ng-if="$index===0 || itemcollection[$index-1].groupkey!==item.groupkey">{{item.groupkey}}</h3>
<label>{{item.name}}</label>
</div>
</div>
And a working fiddle here:
https://jsfiddle.net/vuksyeyh/

Angular update object in array

I wanna update an object within an objects array. Is there another possibility than iterating over all items and update the one which is matching? Current code looks like the following:
angular.module('app').controller('MyController', function($scope) {
$scope.object = {
name: 'test',
objects: [
{id: 1, name: 'test1'},
{id: 2, name: 'test2'}
]
};
$scope.update = function(id, data) {
var objects = $scope.object.objects;
for (var i = 0; i < objects.length; i++) {
if (objects[i].id === id) {
objects[i] = data;
break;
}
}
}
});
There are several ways to do that. Your situation is not very clear.
-> You can pass index instead of id. Then, your update function will be like:
$scope.update = function(index, data) {
$scope.object.objects[index] = data;
};
-> You can use ng-repeat on your view and bind object properties to input elements.
<div ng-repeat="item in object.objects">
ID: <input ng-model="item.id" /> <br/>
Name: <input ng-model="item.name" /> <br/>
</div>
Filters that help in finding the element from the array, can also be used to update the element in the array directly.
In the code below [0] --> is the object accessed directly.
Plunker Demo
$filter('filter')($scope.model, {firstName: selected})[0]
Pass the item to your update method. Take a look at sample bellow.
function MyCtrl($scope) {
$scope.items =
[
{name: 'obj1', info: {text: 'some extra info for obj1', show: true}},
{name: 'obj2', info: {text: 'some extra info for obj2', show: false}},
];
$scope.updateName = function(item, newName){
item.name = newName;
}
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app>
<table ng-controller="MyCtrl" class="table table-hover table-striped">
<tr ng-repeat="x in items">
<td> {{ x.name }}</td>
<td>
Update
<div ng-show="showUpdate" ><input type="text" ng-model="someNewName"> <input type="button" value="update" ng-click="updateName(x, someNewName); showUpdate = false;"></div>
</td>
</tr>
</table>
</body>
Going off your plunker, I would do this:
Change
Edit
to be
Edit
Then use the array index within your $scope.selectSubObject method to directly access your desired element. Something like this:
$scope.selectSubObject = function(idx) {
$scope.selectedSubObject = angular.copy(
$scope.selectedMainObject.subObjects[idx]
);
};
If however, you only have the id to go off of, then you can use the angular filterService to filter on the id that you want. But this will still do a loop and iterate over the array in the background.
See angularjs documentation for ngrepeat to see the variables that it exposes.

Dependant ng-repeat in AngularJS

I have a following data structure coming from REST:
scope.taglist =
[ { name: "mylist", tags: ["tag1", "tag2", "tag3", ...]}, { name:
"mylist2", tags: ["tag2.1", "tag2.2", "tag2.3", ...]} ]
In order to present the names of the objects I have the following html:
<div>
<select ng-model="tagNameSelection">
<option ng-repeat="tagObj in taglist" value="{{tagObj}}">{{tagObj.name}}</option>
</select>
</div>
<div class="tagdetails">
<!-- present the list of tags from tagNameSelection -->
</div>
Now I am a little bit of a loss on how to present the tags list of
individual object. I am able to present the array in raw format (by
sticking {{tagNameSelection}} inside the tagdetails div) but when I
try to iterate through those with ng-repeat angular gives a error
message.
Oddly enough when I hard-code one of the tag lists to the scope in controller the ng-repeat works flawlessly.
Maybe you interesting something like this:
HTML
<div ng-controller="fessCntrl">
<div>
<select ng-model="tagNameSelection"
ng-options="tagObj as tagObj.name for tagObj in taglist"
ng-change="change(tagNameSelection)"></select>
</div>
<pre>{{tagNameSelection.tags|json}}</pre>
<div class="tagdetails">
<ul ng-repeat="tag in tagNameSelection.tags">
<li>{{tag}}</li>
</ul>
</div>
</div>
Controller
var fessmodule = angular.module('myModule', []);
fessmodule.controller('fessCntrl', function ($scope) {
$scope.change = function (value) {
};
$scope.taglist = [{
name: "mylist",
tags: ["tag1", "tag2", "tag3"]
}, {
name: "mylist2",
tags: ["tag2.1", "tag2.2", "tag2.3"]
}]
});
fessmodule.$inject = ['$scope'];
See Fiddle

Resources