angularjs ng-repeat with dynamic json/object - angularjs

I am looking a solution for dynamic data structure(inconsistent like different property name and property length) with ng-repeat. sample code are below.
$scope.data = [{
"table":[{
"employee":"name1",
"value1":"10",
"value2":"20"
},
{
"employee":"name2",
"value1":"15",
"value2":"30"
}]
},
{
"table":[{
"company":"name1",
"compnayValue":"12"
},
{
"company":"name2",
"compnayValue":"12"
}]
}]
<ul>
<li ng-repeat="item in data">
<table>
<tr ng-repeat="row in item.table">
<td>{{??}}</td>
<td>{{??}}</td>
</tr>
</table>
</li>
</ul>

You could enumerate all properties and display their values by another ng-repeat on td:
<li ng-repeat="item in data">
<table>
<tr ng-repeat="row in item.table">
<td ng-repeat="(key, value) in row">
{{row[key]}}
</td>
</tr>
</table>
</li>
but that would break the tabular format of data since some rows would have more tds. To prevent that you could first find out the set of all keys on all rows, do a th repeat with those first and then display them on the corresponding td below, e.g.:
<th ng-repeat="propertyName in allPossiblePropertyNames">
{{propertyName}}
</th>
and
<td ng-repeat="propertyName in allPossiblePropertyNames">
{{row[propertyName ]}}
</td>

Use <tbody> to represent an object inside table array and (key,value) syntax mentioned in iterating over object properties section to iterate over it's properties like:
angular.module('test', []).controller('testCtrl', function($scope) {
$scope.data = [{
"table": [{
"employee": "name1",
"value1": "10",
"value2": "20"
}, {
"employee": "name2",
"value1": "15",
"value2": "30"
}]
}, {
"table": [{
"company": "name1",
"compnayValue": "12"
}, {
"company": "name2",
"compnayValue": "12"
}]
}]
});
ul {
padding: 0;
}
ul li {
list-style-type: none;
margin-bottom: 10px;
}
table {
width: 100%;
table-layout: fixed;
background: #ebebeb;
}
tbody:nth-child(odd) tr {
color: #fff;
background: dodgerblue;
}
tbody:nth-child(even) tr {
color: #fff;
background: hotpink;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="test" ng-controller="testCtrl">
<ul>
<li ng-repeat="item in data">
<table>
<tbody ng-repeat="row in item.table">
<tr ng-repeat="(key, value) in row">
<td>
{{key}}
</td>
<td>
{{value}}
</td>
</tr>
</tbody>
</table>
</li>
</ul>
</div>

Check this plunker, you can define template depends on your data :
https://plnkr.co/edit/fVGhKZy5gnBzuPwspy5s?p=preview
Use angular filter :
app.controller('MainCtrl', function($scope) {
$scope.name = 'World';
$scope.data = [{
"table":[{
"employee":"name1",
"value1":"10",
"value2":"20"
},
{
"employee":"name2",
"value1":"15",
"value2":"30"
}]
},
{
"table":[{
"company":"name1",
"compnayValue":"12"
},
{
"company":"name2",
"compnayValue":"12"
}]
}]
})
.filter('isCompnay', function() {
return function(input) {
console.log(input.employee === undefined)
return input.company ? input : undefined;
};
})
.filter('isEmployee', function() {
return function(input) {
console.log(input.employee === undefined)
return input.employee ? input : undefined;
};
});

Related

Vue v-for nested array

I've got a nested array that I would like to display in a table. However, I can't get my nested array to show correctly.
My data set looks like this:
[
{
"dd":"February",
"md":[
{ "dag":"2020-02-01" },
{ "dag":"2020-02-02" },
{ "dag":"2020-02-03" }
]
},
{
"dd":"March",
"md":[
{ "dag":"2020-03-01" },
{ "dag":"2020-03-02" },
{ "dag":"2020-03-03" }
]
}
]
I would like a table which look like this.
| February | March |
| 2020-02-01 | 2020-03-01 |
| 2020-02-02 | 2020-03-02 |
| 2020-02-03 | 2020-03-03 |
I got this working, but it gives me 2 tables instead of one.
<template v-for="(md2, index) in md2s">
<table :key=index >
<thead >
<tr align="center">
<th style="width: 80px">{{md2}}</th>
</tr>
</thead>
<tr v-for="(date, index) in md2.md" :key=index>
<td align="center" >{{date.dag }}</td>
</tr>
</table>
</template>
All help is appreciated.
br. Erik
You could use a different way to create the loop (one table, multiple columns)
In this case, to populate each header with 'dd' and each column with md elements.
var data=[
{
"dd":"February",
"md":[
{
"dag":"2020-02-01"
},
{
"dag":"2020-02-02"
},
{
"dag":"2020-02-03"
}
]
},
{
"dd":"March",
"md":[
{
"dag":"2020-03-01"
},
{
"dag":"2020-03-02"
},
{
"dag":"2020-03-03"
}
]
}
];
new Vue({
el:'#app',
data:{
md2s: data
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.8/vue.js"></script>
<div id=app >
<table >
<thead >
<tr align="center">
<th v-for="(md2, index) in md2s" :key=index style="width: 80px">{{md2.dd}}</th>
</tr>
</thead>
<tbody>
<tr align="center">
<td v-for="(md2, index) in md2s" :key=index style="width: 80px">
<div v-for="(mdcol, col) in md2.md" :key=col>
{{mdcol.dag}}
</div>
</td>
</tr>
</tbody>
</table>
</div>
https://jsfiddle.net/bn5g1v09/1/
What you need is two diferent iterations. One for the header and another for the table body. For the header, all you need is to add the month name on order. The snippet shows with the computed property months how to do it. This completes the header iteration and the first.
The second one is a little more complex. You need to know beforehand how many lines there will be, for that I made a computed property maxLength that searches over each md and gives the greater one. Then for each row iterate over each month and then verify if the month has enough dates with v-if and if it does look up the desired date from the index and the nested data sctructure. That resumes the second iteration.
The below snippet is a working example with a more complex data showing what could happen with different md sizes and automatic month ordering.
var app = new Vue({
el: '#app',
data: () => ({
nested: [
{ "dd": "February",
"md": [{ "dag": "2020-02-01" },{ "dag": "2020-02-02" },{ "dag": "2020-02-03" },{ "dag": "2020-03-04" }]
},
{ "dd": "March",
"md": [{ "dag": "2020-03-01" },{ "dag": "2020-03-02" },{ "dag": "2020-03-03" }]
},
{ "dd": "January",
"md": [{ "dag": "2020-01-01" }]
}
]
}),
computed: {
staticMonths() {
return Array.from(Array(12),(e,i)=>new Date(25e8*++i).toLocaleString('en-US',{month: 'long'}));
},
months() {
return this.nested.map(item => item.dd).sort((a, b) => {
const A = this.staticMonths.indexOf(a);
const B = this.staticMonths.indexOf(b);
return A-B;
});
},
maxLength() {
return this.nested.reduce((accum, curr) => accum > curr.md.length ? accum : curr.md.length, 0);
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<table>
<thead>
<tr>
<th v-for="(item, index) in months">{{ item }}</th>
</tr>
</thead>
<tbody>
<tr v-for="index in maxLength">
<td v-for="item in months">
<span v-if="nested.find(nest => nest.dd === item).md.length > index-1">
{{nested.find(nest=>nest.dd===item).md[index-1].dag}}
</span>
</td>
</tr>
</tbody>
</table>
</div>

Show nested data from JSON in table angular

I am trying to show nested data from JSON in a table but not getting succeeded.
My json data:-
$scope.data = [
{
"$id": "1",
"Folder": [
{
"Name": "Windows-Desktop",
"CPU": "2",
"RAM": 2,
"FolderName": "Folder-28"
},
{
"Name": "Desktop",
"CPU": "1",
"RAM": 1,
"FolderName": "Folder-11"
}
]
}
]
I tried this in controller:-
$scope.Folder = [];
angular.forEach($scope.data.Folder, function(choose) {
$scope.Folder.push(choose);
}
In view I did this
<tbody>
<tr role="row" class="odd">
<td class="sorting_1" ng-repeat="g in Folder">{{g.Name}}</td>
<td>
<div ng-repeat="g in Folder">
<input class="form-control" type="text">{{g.CPU}}</input>
</div>
</td>
<td>
<div ng-repeat="g in Folder">
<input class="form-control" type="text">{{g.RAM}}</input>
</div>
</td>
</tr>
</tbody>
I am not getting any output in this. Where am I going wrong?
You are accessing $scope.data.Folder which is not correct because $scope.data is an Array.
First try to loop on $scope.data and then a loop on Folder
$scope.Folder = [];
angular.forEach($scope.data, function(choose) {
if(choose && choose.Folder && choose.Folder.length) {
angular.forEach(choose.Folder, function(choose1) {
$scope.Folder.push(choose1);
}
}
}
In your controller do like this:
$scope.Folder = [];
angular.forEach($scope.data, function(choose) {
if(choose && choose.Folder){
$scope.Folder.push(choose.Folder);
}
})
You need to use $scope.data[0].Folder in your controller as $scope.data is a array type. And I am not sure how you are rendering your table but as the question is only related to getting the value in $scope.Folder this is your solution.
var myApp = angular.module('myApp', []);
//myApp.directive('myDirective', function() {});
//myApp.factory('myService', function() {});
function MyCtrl($scope) {
$scope.data = [
{
"$id": "1",
"Folder": [
{
"Name": "Windows-Desktop",
"CPU": "2",
"RAM": 2,
"FolderName": "Folder-28"
},
{
"Name": "Desktop",
"CPU": "1",
"RAM": 1,
"FolderName": "Folder-11"
}
]
}
];
$scope.Folder = [];
angular.forEach($scope.data[0].Folder, function(choose) {
$scope.Folder.push(choose);
});
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="MyCtrl">
<tbody>
<tr role="row" class="odd">
<td class="sorting_1" ng-repeat="g in Folder">{{g.Name}}</td>
<td>
<div ng-repeat="g in Folder">
<input class="form-control" type="text" />{{g.CPU}}
</div>
</td>
<td>
<div ng-repeat="g in Folder">
<input class="form-control" type="text" />{{g.RAM}}
</div>
</td>
</tr>
</tbody>
</div>
Here is one more example that I think is something you are expecting
var myApp = angular.module('myApp', []);
//myApp.directive('myDirective', function() {});
//myApp.factory('myService', function() {});
function MyCtrl($scope) {
$scope.data = [
{
"$id": "1",
"Folder": [
{
"Name": "Windows-Desktop",
"CPU": "2",
"RAM": 2,
"FolderName": "Folder-28"
},
{
"Name": "Desktop",
"CPU": "1",
"RAM": 1,
"FolderName": "Folder-11"
}
]
}
];
$scope.Folder = [];
angular.forEach($scope.data[0].Folder, function(choose) {
$scope.Folder.push(choose);
});
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="MyCtrl">
<table border='1'>
<tr>
<th>Name</th>
<th>CPU</th>
<th>RAM</th>
</tr>
<tr ng-repeat = "g in Folder">
<td>{{g['Name']}}</td>
<td>{{g['CPU']}}</td>
<td>{{g['RAM']}}</td>
</tr>
</table>
</div>
You can try the following
<div ng-repeat="item in data">
<div ng-repeat="g in item.Folder">
Name:{{g.Name}}-
Cpu:{{g.CPU}}-
Ram:{{g.RAM}}
</div>
</div>
using above method would eliminate the need of preparing data in your controller
Demo
Table Demo
All you need to do is update your iterator function
from
angular.forEach($scope.data.Folder, function(choose)
to
angular.forEach($scope.data[0].Folder, function(choose)
look at your json Folder is first element....

Creating dynamic table using AngularJS and restful api

I'm trying to create a table using Quandl restful api along with AngularJS. While table headers created well table rows aren't filled with data at all, there are only empty rows.
Here is my controller:
angular.module('stockControllers', [])
.controller('stockController', function($scope, $http){
var results = {};
$http.get('https://www.quandl.com/api/v3/datasets/WIKI/FB.json?start_date=2017-11-01&api_key=3pg7TVEyogz6D6FXhf5g').
then(function(response) {
$scope.resulting = response.data;
console.log($scope.resulting);
});
});
HTML code:
<div ng-controller="stockController">
<div class='page-header'>
<h1> {{resulting.dataset.name}} </h1>
<p> Note: showing only OHLC data </p>
</div>
<table class="table table-striped">
<tr>
<th>{{resulting.dataset.column_names[0]}}</th>
<th>{{resulting.dataset.column_names[1]}}</th>
<th>{{resulting.dataset.column_names[2]}}</th>
<th>{{resulting.dataset.column_names[3]}}</th>
<th>{{resulting.dataset.column_names[4]}}</th>
</tr>
<tr ng-repeat="row in resulting.dataset.data">
<td>{{resulting.dataset.data[row][0]}}</td>
<td>{{resulting.dataset.data[row][1]}}</td>
<td>{{resulting.dataset.data[row][2]}}</td>
<td>{{resulting.dataset.data[row][3]}}</td>
<td>{{resulting.dataset.data[row][4]}}</td>
</tr>
</table>
</div>
And api response fragment which I want to use:
"dataset": {
"column_names": ["Date","Open","High","Low","Close","Volume","Ex-Dividend","Split Ratio","Adj. Open","Adj. High","Adj. Low","Adj. Close","Adj. Volume"],
"data": [["2017-11-13",
177.5,
179.04,
177.3,
178.77,
9431449,
0,
1,
177.5,
179.04,
177.3,
178.77,
9431449 ],,
[
"2017-11-10",
178.35,
179.0999,
177.96,
178.46,
10933405,
0,
1,
178.35,
179.0999,
177.96,
178.46,
10933405 ],,
angular.module('app', []).controller('ctrl', function($scope) {
$scope.resulting = {
dataset: {
column_names: ["Date", "Open", "High", "Low", "Close", "Volume", "Ex-Dividend", "Split Ratio", "Adj. Open", "Adj. High", "Adj. Low", "Adj. Close", "Adj. Volume"],
data: [
["2017-11-13",
177.5,
179.04,
177.3,
178.77,
9431449,
0,
1,
177.5,
179.04,
177.3,
178.77,
9431449
],
[
"2017-11-10",
178.35,
179.0999,
177.96,
178.46,
10933405,
0,
1,
178.35,
179.0999,
177.96,
178.46,
10933405
]
]
}
}
});
table,
th,
td {
border: 1px solid black;
border-collapse: collapse;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<table ng-app='app' ng-controller='ctrl'>
<thead>
<tr>
<th ng-repeat='head in resulting.dataset.column_names' ng-if='$index < 5'>{{head}}</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="row in resulting.dataset.data">
<td ng-repeat='val in row track by $index' ng-if='$index < 5'>{{val}}</td>
</tr>
</tbody>
</table>

Sorting only certain arrays in nested ngRepeat

I currently have a nested ngRepeat, where the inner loop iterates over a collection of items from its parent. An excerpt:
<div ng-repeat="person in persons">
(Irrelevant code here.)
<table>
<tr>
<th ng-click="setItemOrder('name')">Item name</th>
<th ng-click="setItemOrder('number')">Item number</th>
</tr>
<tr ng-repeat="item in person.items | orderBy:itemOrder">
<td>{{item.name}}
<td>{{item.number}}
</tr>
</table>
</div>
By clicking the table headers, I set the itemOrder-property in my controller to the name of the property I want orderBy to use:
$scope.setItemOrder = function(order){
$scope.itemOrder = order;
}
This all works fine, except that if I click the headers in one person-div, the item-tables in all person-divs get sorted on that property.
Is there a way to make ngRepeat only apply orderBy to entries that match a certain criteria - for instance a certain index? Or should I use a different approach?
Try setting the property to respective person instance as follows:
angular.module('test', []).controller('testController', function($scope) {
$scope.persons = [{
items: [{
name: 'test',
number: 2
}, {
name: 'test1',
number: 1
}]
}, {
items: [{
name: 'test3',
number: 5
}, {
name: 'test4',
number: 4
}]
}];
$scope.setItemOrder = function(person, order) {
person.itemOrder = order;
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<form ng-app="test" ng-controller="testController">
<div ng-repeat="person in persons">
<table>
<tr>
<th ng-click="setItemOrder(person,'name')">Item name</th>
<th ng-click="setItemOrder(person,'number')">Item number</th>
</tr>
<tr ng-repeat="item in person.items | orderBy:person.itemOrder">
<td>{{item.name}}
<td>{{item.number}}
</tr>
</table>
</div>
You could add a ordering variable for each person and extend setItemOrder with the person object. Then you can call:
setItemOrder(person, 'name');
and then use it in the ngRepeat:
orderBy:person.itemOrder
angular.module('test', []).controller('testController', function($scope) {
$scope.ordersort=true;
$scope.orderfield='number';
$scope.persons = {
"items": [{
"name": 'test',
"number": 2
}, {
"name": 'test1',
"number": 1
}],
"item1": [{
"name": 'test3',
"number": 5
}, {
"name": 'test4',
"number": 4
}]
};
$scope.setItemOrder = function(person, order) {
$scope.orderfield=order;
person.itemOrder = order;
$scope.ordersort= !$scope.ordersort;
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<form ng-app="test" ng-controller="testController">
<div ng-repeat="person in persons">
<table>
<tr>
<th ng-click="setItemOrder(person,'name')">Item name</th>
<th ng-click="setItemOrder(person,'number')">Item number</th>
</tr>
<tr ng-repeat="item in person | orderBy:orderfield:ordersort">
<td>{{item.name}}
<td>{{item.number}}
</tr>
</table>
</div>
I have modified your example. In this example table sorting is working perfectly. But It is not sorted the particular table when I click on that table header. Anyway to sort columns by specific table?
angular.module('test', []).controller('testController', function($scope) {
$scope.persons = [{
items: [{
name: 'test',
number: 2
}, {
name: 'test1',
number: 1
}]
}, {
items: [{
name: 'test3',
number: 5
}, {
name: 'test4',
number: 4
}]
}];
$scope.setItemOrder = function(person, order) {
person.itemOrder = order;
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<form ng-app="test" ng-controller="testController">
<div ng-repeat="person in persons">
<table>
<tr>
<th ng-click="setItemOrder(person,'name')">Item name</th>
<th ng-click="setItemOrder(person,'number')">Item number</th>
</tr>
<tr ng-repeat="item in person.items | orderBy:person.itemOrder">
<td>{{item.name}}
<td>{{item.number}}
</tr>
</table>
</div>

AngularJs ng-repeat 2D array in table, each subarray one column

I have an array and I need to put that array in table.
$scope.testArr=[
{'first':[
{ 'value':'1_1', 'rolle':'one1' },
{ 'value':'2_1', 'rolle':'two1' },
{ 'value':'3_1', 'rolle':'three1'}
]
},
{'second': [
{ 'value':'1_2', 'rolle':'one2' },
{ 'value':'2_2', 'rolle':'two2' },
{ 'value':'3_2', 'rolle':'three2' }
]
}
];
Resulting table should have 4 columns, each subarray should be one(or two) column(s). Like this:
one1 | 1_1 | one2 | 1-2
two1 | 2_1 | two2 | 2_2
three1|3_1 | three2|3_2
So far I got this. Its only the first subarray:
<table>
<tbody ng-repeat="test in testArr">
<tr ng-repeat="t1 in test.first">
<td> {{t1.rolle}} </td>
<td> {{t1.value}} </td>
</tr>
</tbody>
</table>
How can I add the second subarray as column? It's not necessary need to be a table.
var app = angular.module('app', []);
app.controller('mainCtrl', function ($scope) {
$scope.testArr = [{
'first': [{
'value': '1_1',
'rolle': 'one1'
}, {
'value': '2_1',
'rolle': 'two1'
}, {
'value': '3_1',
'rolle': 'three1'
}]
}, {
'second': [{
'value': '1_2',
'rolle': 'one2'
}, {
'value': '2_2',
'rolle': 'two2'
}, {
'value': '3_2',
'rolle': 'three2'
}]
}];
});
td {
border:solid 1px grey
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app">
<div ng-controller="mainCtrl">
<table>
<tbody ng-repeat="test in testArr">
<tr ng-repeat="t1 in test.first">
<td>{{t1.rolle}}</td>
<td>{{t1.value}}</td>
<td>{{testArr[1].second[$index].rolle}}</td>
<td>{{testArr[1].second[$index].value}}</td>
</tr>
</tbody>
</table>
</div>
</div>

Resources