ng-repeat loop through object is not behaving properly - angularjs

In my Angularjs ng-repeat is have following only one object, fields are reduced actually i have more than 40 in this object. if i have 40 fields then 40 empty output is rendering (see below outout).
{"Name": "Raj", "Gender":"M", "Country": "India"} (ONLY ONE OBJECT)
Angular View
<table ng-repeat="emp in model.Employee">
<tr>
<td><strong>Name:</strong></td>
<td>{{emp.Name}}</td>
</tr>
<tr>
<td><strong>Gender:</strong></td>
<td>{{emp.Gender}}</td>
</tr>
</table>
Excepted output is
Name: Raj
Gender: M
But the actual out put is rendering three time without value.
Name:
Gender:
Name:
Gender:
Name:
Gender:

This is happening because you are iterating over an object instead of an array. So, the ngRepeat loop will run as many times as there are keys in your object. Since, there are three keys in the object, the loop is being run thrice. Also, emp(the iterable) is the key('Name', 'Gender', 'Country') instead of the complete object.
Change to :
[{"Name": "Raj", "Gender":"M", "Country": "India"}]

you can use (key,value) for this purpose.
var app = angular.module("app",[])
app.controller('ctrl',['$scope', function($scope){
$scope.data ={"Name": "Raj", "Gender":"M", "Country": "India"};
}]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.22/angular.min.js"></script>
<div ng-app="app" ng-controller="ctrl">
<div class="item item-checkbox">
<table >
<tr ng-repeat="(key,value) in data" ng-if="key != 'Country'">
<td>{{key}}</td>
<td>{{value}}</td>
</tr>
</table>
</div>

Related

Angularjs allows data updates only for the first rows

I have a code that displays three rows of information from json using angularjs.
Now I want if any values entered in the form inputs corresponding to that rows to replace the already existing values in the view for that rows.
Eg. In row 1 , I have value hello sub 1 for subcomment Variable. Now I want if I enter another values say New sub 1 in the form inputs on that, it will replace/updates the already existing values in the **angular view ** for that rows.
The problem with the code above is that it keeps on replacing/updating only the subcomment values of the first row each time a new subcomment is entered. irrespective of the save button that was clicked
I don't know whether problem is from in the line of code below
$scope.posts[index].comment[0].subcomment = subcomment;
below is the entire partially working code which keeps updating only the first row no matter which submit button that was clicked
html
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app="test" ng-controller="testCtrl">
<div ng-repeat='post in posts'>
<b>Post Title:</b> {{ post.title }}
<div ng-repeat='comment in post.comment'>
<br>
<b>sub comment</b>: {{comment.subcomment}}
<div>
<table>
<tr>
<tr>
<td>Enter subcomment</td>
<td>
<input type='text' ng-model='subcomment' placeholder="Enter Value For subcomment and Save.">
</td>
</tr>
<tr>
<td> </td>
<td>
<input type='button' id='but_save' value='Save and Replace/Update' ng-click='setResponse4(post.id,1,$index,subcomment,comment.id)'>
</td>
<td>
<input type='button' style="display:none" ng-init='getComments1(comment.id,5)'>
</td>
</tr>
</table>
</div>
</div>
<hr style="width:100%;font-size:10">
</div>
</body>
js
var app = angular.module('test', []);
app.controller('testCtrl', function ($scope, $http) {
$scope.posts = [
{
"id": "1",
"title": "my first title.",
"comment": [
{
"subcomment": "Hello sub 1"
}
]
},
{
"id": "2",
"title": "my second title.",
"comment": [
{
"subcomment": "Hello sub 2"
}
]
},
{
"id": "3",
"title": "my third title.",
"comment": [
{
"subcomment": "Hello sub 3"
}
]
}
];
//initialize an arrays of comments
$scope.commenting = [];
$scope.setResponse4 = function (postid, type, index, subcomment, commentid) {
var subcomment = subcomment;
alert(subcomment);
$scope.posts[index].comment[0].subcomment = subcomment;
}
});
Screenshot is attached
The problem in your code is you have 2 ng-repeats and $index passes the index of the inner ng-repeat whereas you need the index of the outer ng-repeat if you modify your code to take the index of outer ng-repeat as following, it should solve your issue.
1) First add this ng-init to your outer ng-repeat
<div ng-repeat='post in posts track by $index' ng-init="outerIndex=$index">
2) use outerIndex in your save function
<input type='button' id='but_save' value='Save and Replace/Update' ng-click='setResponse4(post.id,1,outerIndex,subcomment,comment.id)'>
Demo
Yes as the code says, you are accessing only the specific index of the array and setting the 0th element value,
$scope.posts[index].comment[0].subcomment = subcomment;
in order to set all values you can use angular.forEach
angular.forEach($scope.posts[index].comment, function(value, key){
value.subcomment = subcomment;
}

unable to loop through an string array within angular ng-repeat

I have a Java object returned from a servlet which I convert into a JSON and fed back to angular as a scope variable to be displayed.
This Java object along with some string variables has a string array.
This is how the JSON looks: (the below JSON is stored on $scope.detail)
{"details":
{"0":{"Var1":"val1","Var2":"val2","Arr1":["0","0","2",null,null,null]},
{"1":{"Var1":"val1","Var2":"val2","Arr1":["0","0","2",null,null,null]}
}
I am able to successfully iterate over the items using ng-repeat except for "Arr1". A few responses on the website show that I should be able to iterate using another ng-repeat but the below doesn't work for me. Please suggest. Thank You.
<table ng-repeat="item in detail.details">
<tr>
<td>item.Var1</td>
<td>item.Var2</td>
<td>
<div ng-repeat="val in item.Arr1">
{{val}}
</div>
</td>
</tr>
</table>
The JSON you have provided is not valid JSON.
With the least modifications, I would suggest re-formatting it to look something like this:
{
"details": [
{
"Var1":"val1","Var2":"val2","Arr1":["0","0","2",null,null,null]
},
{
"Var1":"val1","Var2":"val2","Arr1":["0","0","2",null,null,null]
}
]
}
Although this is now valid JSON, I still think you should consider reformatting your JSON even more to easily consume it by the AngularJS app.
Here is a Plunker to illustrate a solution.
Check your JSON, it is not valid. The 2nd property of your details object is not structured well check for { and }, they are not placed correctly.
You can use https://jsonformatter.curiousconcept.com/ to restructure your JSON and check of errors
Below is the corrected JSON:
{
"details":{
"0":{
"Var1":"val1",
"Var2":"val2",
"Arr1":[
"0",
"0",
"2",
null,
null,
null
]
},
"1":{
"Var1":"val1",
"Var2":"val2",
"Arr1":[
"0",
"0",
"2",
null,
null,
null
]
}
}
}
Your HTML seams OK, just add track by $index and print your item.Var1 and item.Var2 using interpolate operator
<table ng-repeat="item in detail.details">
<tr>
<td>{{item.Var1}}</td>
<td>{{item.Var2}}</td>
<td>
<div ng-repeat="val in item.Arr1 track by $index">
{{val}}
</div>
</td>
</tr>
</table>
I hope this helps
Some observations as per your code :
Your JSON is not valid
It should be structured like this :
use ng-repeat="(key,val) in detail.details" instead of ng-repeat="item in detail.details" as detail.details is an object not an array.
DEMO
var myApp = angular.module('myApp',[]);
myApp.controller('MyCtrl', function($scope) {
$scope.detail = {
"details": {
"0": {
"Var1": "val1",
"Var2": "val2",
"Arr1": ["0", "0", "2", null, null, null]
},
"1": {
"Var1": "val1",
"Var2": "val2",
"Arr1": ["0", "0", "2", null, null, null]
}
}
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="MyCtrl">
<table ng-repeat="(key,val) in detail.details">
<tr>
<td>{{val.Var1}}</td>
<td>{{val.Var2}}</td>
<td>
<div ng-repeat="item in val.Arr1">
{{item}}
</div>
</td>
</tr>
</table>
</div>

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

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.

How to implement angular nested ng-repeat with groupBy filter and ng-model binding on input

I'm trying to create a nested ng-repeat loop. It uses the groupBy and toArray filters from angular-filter.
The issue is that I have an editable input field in the nested array. Without implementing "track by" on the ng-repeats every time the value changes when typed it looses focus as described in this issue.
If I try to put a track by on the repeats it breaks and shows many fields with blank values. Is there any way to correctly implement track by in this situation so that the repeats display correctly and I can type into the input field without it losing focus?
Here is example, if you run it you will see as soon as you edit input you loose focus:
var app = angular.module('App', ['angular.filter']);
app.controller('MainCtrl', function() {
this.Parts = [{
Id: 1,
ShortDescription: "Premium Shocks",
SupplierSku: "ZXU3322",
SellPrice: 110,
SellPriceInclGst: 130,
ProfitExclGst: 10,
SupplierName: 'Super Sports',
Quantity: 3
}, {
Id: 2,
ShortDescription: "Spanner",
SupplierSku: "4444",
SellPrice: 44,
SellPriceInclGst: 130,
ProfitExclGst: 10,
SupplierName: 'Bobs Parts',
Quantity: 1
}, {
Id: 3,
ShortDescription: "Spark Plugs",
SupplierSku: "xxxxx",
SellPrice: 10,
SellPriceInclGst: 130,
ProfitExclGst: 10,
SupplierName: 'Bobs Parts',
Quantity: 5
}]
});
<html>
<head>
<script src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.15/angular.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/angular-filter/0.5.4/angular-filter.min.js"></script>
</head>
<body ng-app="App">
<table class="table" ng-controller='MainCtrl as main'>
<thead>
<tr>
<th>Short Descriptin</th>
<th>SKU</th>
<th>Qty</th>
<th>Unit Price</th>
<th>Total</th>
<th>Total + GST</th>
</tr>
</thead>
<tbody ng-repeat="supplier in main.Parts | groupBy:'SupplierName' | toArray:true | orderBy:'$key'">
<tr class="title-display-row">
<td colspan="6">{{ supplier.$key }}</td>
</tr>
<tr ng-repeat="item in supplier track by $index">
<td>{{ item.ShortDescription }} {{ key }}</td>
<td>{{ item.SupplierSku }}</td>
<td class="field-cell">
<div class="field-wrap">
<input type="text" name="quantity[$index]" ng-model="item.Quantity" />
</div>
</td>
<td>{{ item.SellPrice | currency }}</td>
<td>Total</td>
<td>Total-gst</td>
</tr>
</tbody>
</table>
</body>
</html>
Any suggestions greatly appreciated.
In the unlikely event someone has the same problem as this... the solution was to remove the toArray|true filter.
Then instead of accessing the supplier name with {{ supplier.$key }} I'm using {{ Supplier[0].SupplierName }}. Because each supplier in the loop is an array of items with the same supplier name so I can just take the first and use it.

angularjs ng-repeat inside ng-repeat,the inside array can't update

I come from China,my English very poor,so I do a demo.how can I update array inside ng-repeat?
The HTML:
<body ng-app="main" ng-controller="DemoCtrl">
<table ng-table class="table">
<tr ng-repeat="user in users">
<td data-title="'Name'">{{user.name}}</td>
<td data-title="'Age'">{{user.age}}</td>
<td>
{{user.spms|json}}
<div ng-repeat="u in user.spms">
<span ng-bind="u"></span>
<input type="text" ng-model="u" ng-change='updateArray($parent.$index, $index, u)'>
</div>
</td>
</tr>
</table>
</body>
The JS:
var app = angular.module('main', []).
controller('DemoCtrl', function($scope) {
$scope.users = [{
name: "Moroni",
age: 50,
spms: [
6135.7678,
504.4589,
2879.164,
669.7447
]
},
{
name: "seven",
age: 30,
spms: [
34135.7678,
5034.42589,
22879.1264,
63469.72447
]
}
];
$scope.updateArray = function(parent, index, u) {
$scope.users[parent].spms[index] = u * 1; // multiply by one to keep the value a Number
}
})
There are issues here are every update is changing the scope, so you can only change one time them click then change - so I would recommend add a update values button and implementing more or less the same logic to update the array values.
DEMO

Resources