Iterating over JSON properties - angularjs

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"

Related

How can i make dynamic ng-repeat using angularjs?

Below I have added my data
[{
"name":"testapp",
"version":"2.0",
"description":"testapp",
"applicationenvironment":"angularjs"
}]
I want to make ng-repeat but I don't want to hard code any field (name, version, description, applicationenvironment)
How can I achieve this?
MY expectation :
IN TABLE it should come like this
Your array should be an object. So your structure simplifies quite a lot. Just extract key and values from your object and loop over it for each row. Then display key and values in separate columns per row:
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.table = [{
"name": "testapp",
"version": "2.0",
"description": "testapp",
"applicationenvironment": "angularjs"
}]
});
<!DOCTYPE html>
<html>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.9/angular.min.js"></script>
<body>
<div ng-app="myApp" ng-controller="myCtrl">
<table>
<tr>
<th>Key</th>
<th>Value</th>
</tr>
<tr ng-repeat="(key, value) in table[0]">
<td>{{key}}</td>
<td>{{value}}</td>
</tr>
</table>
</div>
</body>
</html>
Although I don't recommend you to have this strucuture, you can do something like this:
angular.module('app', [])
.controller('appController', function () {
this.data = {
"name":"testapp",
"version":"2.0",
"description":"testapp",
"applicationenvironment":"angularjs"
};
});
And your HTML would be something like this:
<div ng-app="app" ng-controller="appController as vm">
<ul>
<li ng-repeat="(key, value) in vm.data"> {{ key }} : {{ value }}</li>
</ul>
</div>
If you still need to have the data inside an array as you've wrote in the question, you would have to iterate over both the array and the object.
Now since your data source is an array, you need to do two nested ng-repeats
let app = angular.module("table",[]);
app.controller("tableCtrl", ["$scope", function($scope){
$scope.data = [{
"name":"testapp",
"version":"2.0",
"description":"testapp",
"applicationenvironment":"angularjs"
},
{
"name":"testapp 2",
"version":"2.1",
"description":"testapp 2",
"applicationenvironment":"angularjs"
}];
}]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="table" ng-controller="tableCtrl">
<table ng-repeat="row in data">
<tr><td>Key</td><td>Value</td></tr>
<tr ng-repeat="(key,value) in row">
<td>{{key}}</td><td>{{value}}</td>
</tr>
</table>
</div>
Now if you do this, your data structure should yield the wanted result
You need to loop twice: Once through each the entire array of objects to access each object, and then inside each object to access individual key-value pairs.
I have posted the code below:
angular.module('app', [])
.controller('Controller1', function () {
this.data = {
"name":"testapp",
"version":"2.0",
"description":"testapp",
"applicationenvironment":"angularjs"
};
});
<div ng-app="app" ng-controller="Controller1 as c1">
<table>
<tr>
<th>Key</th>
<th>Value</th>
</tr>
<tr ng-repeat="c in c1.data">
<table>
<tr ng-repeat="(key, value) in c">
<td> {{ key }} </td>
<td> {{ value }} </td>
</tr>
</table>
</tr>
</table>
</div>

Give a specific color to even/odd row using angularJS directive no CSS

<table>
<tr ng-repeat="customer in myData"
ng-if="$even" style="background-color: gray">
<td>{{$index+1}}</td>
<td>{{customer.name}}</td>
<td>{{customer.city}}</td>
</tr>
</table>
I got the data from a JSON file and display in view.I need a specific color for even/odd row using angularJS directive. Please help me. Advance thanks.
You could track by $index and determine if the row is odd or even, then set the style based off a ternary operator using the ngStyle style directive.
However, I would recommend using the ngClass directive which would give you better separation between markup and styles, and also make the DOM cleaner.
As an example:
<li ng-repeat="item in tc.list track by $index" ng-class="$index % 2 == 0 ? 'even' : 'odd'">{{item}}</li>
Full Snippet:
var app = angular.module("TestApp",[]);
app.controller("TestController", function() {
var vm = this;
vm.list = [];
function populateDummyItems() {
vm.list.push("One");
vm.list.push("Two");
vm.list.push("Three");
vm.list.push("Four");
}
populateDummyItems();
});
.even {
background-color: lightblue;
}
.odd {
background-color: yellow;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app="TestApp">
<h1>Darren's test application!</h1>
<ul ng-controller="TestController as tc">
<li ng-repeat="item in tc.list track by $index" ng-class="$index % 2 == 0 ? 'even' : 'odd'">{{item}}</li>
</ul>
</body>
External Plunker:
https://plnkr.co/edit/4LSB0oKYr0VgSQj0jTxP?p=preview
If you don't want to use css, you can try ng-style
<table>
<tr ng-repeat="customer in myData" ng-style="{'background-color':$even?evenColor:oddColor}">
<td>{{$index+1}}</td>
<td>{{customer.name}}</td>
<td>{{customer.city}}</td>
</tr>
</table>
js
$scope.evenColor = 'yellow'; // you can also enter the hex '#ffff00' here
$scope.oddColor = 'red';
If you don't want to use Stylesheets, you can use the angular ngStyle attribute
https://docs.angularjs.org/api/ng/directive/ngStyle
example:
HTML:
<div ng-app="OddEven">
<ul ng-controller="oddEvenController">
<li ng-repeat="item in list" ng-style="$index % 2 == 0 ? {'color':'blue'} : {color:'red'}">{{item}}</li>
</ul>
</div>
JS:
var angularApp = angular.module("OddEven",[]);
angularApp.controller("oddEvenController", function($scope) {
$scope.list = ["a", "b", "c", "d", "e", "f"];
});
If you can use Stylesheets, look at the accepted answer of
How to assign alternate class to rows in Angular JS?

How i can bind json data in html table using angular js?

Here is my json data. How I can bind this data in HTML table using angular.js?
[{"keycolumn1":1,"originkey1":1,"datafield1":1},
{"keycolumn1":2,"originkey1":2,"datafield1":2},
{"keycolumn1":3,"originkey1":3,"datafield1":3},
{"keycolumn1":4,"originkey1":4,"datafield1":4},
{"keycolumn1":5,"originkey1":5,"datafield1":5},
{"keycolumn1":11,"originkey1":11,"datafield1":11},
{"keycolumn1":12,"originkey1":12,"datafield1":12},
{"keycolumn1":13,"originkey1":13,"datafield1":13},
{"keycolumn1":14,"originkey1":14,"datafield1":14},
{"keycolumn1":15,"originkey1":15,"datafield1":15}]
There are many ways to display the json data in angular,
you can bind your json as
ng-repeat
<tr ng-repeat="values in data">
nested ng-repeat depending on the json format
ng-repeat with 'track by' while dealing with index values
<tr ng-repeat="item in rows">
<td>{{item.project}}({{item.task}})</td>
<td ng-repeat="values in item.hour track by $index">
<input type="number" ng-model="item.hour[$index]"/>
</td>
</tr>
ng-repeat with key value pairs
<tr ng-repeat="(key, value) in data">
<td> {{key}} </td> <td> {{ value }} </td>
</tr>
In your case, best option is to use basic ng-repeat as
<tr ng-repeat="values in data">
<td>{{values.keycolumn1}}</td>
<td>{{values.originkey1}}</td>
<td>{{values.datafield1}}</td>
</tr>
Just try like this,
var appReminder = angular.module('testApp', []);
appReminder.factory('testFactory', function ($http) {
return {}
});
appReminder.controller('testController', function PostController($scope, testFactory, $timeout)
{
$scope.result_function = function ()
{
$scope.respose = [
{"keycolumn1":1,"originkey1":1,"datafield1":1},
{"keycolumn1":2,"originkey1":2,"datafield1":2},
{"keycolumn1":3,"originkey1":3,"datafield1":3},
{"keycolumn1":4,"originkey1":4,"datafield1":4},
{"keycolumn1":5,"originkey1":5,"datafield1":5},
{"keycolumn1":11,"originkey1":11,"datafield1":11},
{"keycolumn1":12,"originkey1":12,"datafield1":12},
{"keycolumn1":13,"originkey1":13,"datafield1":13},
{"keycolumn1":14,"originkey1":14,"datafield1":14},
{"keycolumn1":15,"originkey1":15,"datafield1":15}];
;}
$scope.result_function();
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="testApp" data-ng-controller="testController">
<table border="1">
<tr>
<th>Keycolumn</th>
<th>Originkey</th>
<th>Datafield</th>
<tr>
<tr ng-repeat="item in respose">
<td>{{item.keycolumn1}}</td>
<td>{{item.originkey1}}</td>
<td>{{item.datafield1}}</td>
</tr>
</table>
</div>
Do you mean to display the json content in a html table?
$scope.json = [
{"keycolumn1":1,"originkey1":1,"datafield1":1},
{"keycolumn1":2,"originkey1":2,"datafield1":2},
{"keycolumn1":3,"originkey1":3,"datafield1":3},
{"keycolumn1":4,"originkey1":4,"datafield1":4},
{"keycolumn1":5,"originkey1":5,"datafield1":5},
{"keycolumn1":11,"originkey1":11,"datafield1":11},
{"keycolumn1":12,"originkey1":12,"datafield1":12},
{"keycolumn1":13,"originkey1":13,"datafield1":13},
{"keycolumn1":14,"originkey1":14,"datafield1":14},
{"keycolumn1":15,"originkey1":15,"datafield1":15}];
in html you can use ng-repeat
<table>
<tr ng-repeat="r in json">
<td>{{r.keycolumn1}}</td>
<td>{{r.originkey1}}</td>
<td>{{r.datafield1}}</td>
</tr>
</table>
Store this in a json file (data.json). Use $http to get this data as a response and store it in a $scope variable.
For Example:
$http.get("data.json").then(function(response) {
$scope.data = response.data;
});
you need to assign your json to a scope variable like below
$scope.data="your data";
now using this data you can loop in table by using ng-repeat
here is a sample plunker with your data
Simple using ng-repeat by having your json Data in your controller
<table>
<tr ng-repeat="r in jsonData">
<td>{{r.keycolumn1}}</td>
<td>{{r.originkey1}}</td>
<td>{{r.datafield1}}</td>
</tr>
</table>
Also you can have it in your Json file like this
{
"data":[
{
"keycolumn1":1,
"originkey1":1,
"datafield1":1
},
{
"keycolumn1":2,
"originkey1":2,
"datafield1":2
},
{
"keycolumn1":3,
"originkey1":3,
"datafield1":3
},
{
"keycolumn1":4,
"originkey1":4,
"datafield1":4
},
{
"keycolumn1":5,
"originkey1":5,
"datafield1":5
},
{
"keycolumn1":11,
"originkey1":11,
"datafield1":11
},
{
"keycolumn1":12,
"originkey1":12,
"datafield1":12
},
{
"keycolumn1":13,
"originkey1":13,
"datafield1":13
},
{
"keycolumn1":14,
"originkey1":14,
"datafield1":14
},
{
"keycolumn1":15,
"originkey1":15,
"datafield1":15
}
]
}
and use it in your controller like this
$http.get('jsonData.json').success(function(data) {
$scope.jsonFileData = data.data;
});
and I have made a working LIVE PLUNK which contains both examples
First you need to associate controller with view then you can access variables of controller in view.
<div ng-controller="controllername as vm">
<table>
<tr ng-repeat="anyvariable in vm.json">
<td>{{anyvariable.keycolumn1}}</td>
<td>{{anyvariable.originkey1}}</td>
<td>{{anyvariable.datafield1}}</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.

Two way binding is not working with angular js

I have the html code like this:
<div ng-controller="MainCtrl">
<tr data-ng-repeat="element in awesomeThings">
<div ng-if="$even">
<td ng-click="getServiceDetails(element)">
<a href="#">
{{element['serviceDetail']['name']}}
</a>
</td>
</div>
</tr>
//after some html
<span >{{publicName}}</span>
</div>
My controller looks like this:
angular.module('dcWithAngularApp')
.controller('MainCtrl', function ($scope,$http,test) {
$scope.awesomeThings = {"serviceDetail":{"name":"batman"}}
$scope.getServiceDetails = function(serviceDetails)
{
console.log('Called')
$scope.publicName = serviceDetails.name
}
});
After clicking on the td tag, the span text are not changing! Even though me changing the publicName in the current scope!
Where I'm making the mistake?
You don't have a name property in your $scope.awesomeThings array.
Here I added some animals for you.
angular.module('dcWithAngularApp')
.controller('MainCtrl', function ($scope,$http,test) {
$scope.awesomeThings = [
{ name: "Dog" },
{ name: "Cat" }
];
$scope.getServiceDetails = function(serviceDetails)
{
console.log('Called')
$scope.publicName = serviceDetails.name
}
});
Edit:
I put together a JSFiddle that solves your edit.
http://jsfiddle.net/HB7LU/7191/
$scope.awesomeThings is an array of string so element does not have a 'name' property.
You also have a missing ; after your console.log which may be stopping the code from running.
It may help you to log what the object is.
<div ng-controller="MainCtrl">
<tr data-ng-repeat="element in awesomeThings">
<div ng-if="$even">
<td ng-click="getServiceDetails(element)">
<a href="#">
{{element.name}}
</a>
</td>
</div>
</tr>
//after some html
<span >{{publicName}}</span>
</div>
angular.module('dcWithAngularApp')
.controller('MainCtrl', function ($scope,$http,test) {
$scope.awesomeThings = {"serviceDetail":{"name":"batman"}};
$scope.getServiceDetails = function(serviceDetails)
{
console.log(serviceDetails);
$scope.publicName = serviceDetails.name;
}
});
Your main issue is this:
$scope.publicName = serviceDetails.name
It needs to be
$scope.publicName = serviceDetails;
$scope.awesomeThings is an array of strings, not objects. You're ng-repeating through the string array and passing the string to your getServiceDetails method, so 'serviceDetails' is just a string.
As an unrelated warning, I see you're using tr inside a div. The tr should be inside a table, thead, or tbody.

Resources