I'm learning Angular and came across some difficulty when creating table from nested collection.
I simplified a bit my data and table for this example. Please help ;)
Here is what I want to achieve (note continent and country can span across multiple columns):
Continent: | Europe | Asia |
Country: | UK | Spain | China |
City: | Edinburgh | London | Barcelona | Beijing |
Population:| 500000 | 9000000 | 15000000 | 22000000 |
Here is data structure:
function playerCtrl($scope) {
$scope.continents = [
{
"continent": "Europe",
"columnSpan": 3,
"countries": [
{
"country": "UK",
"columnSpan": 2,
"cities": [
{
"city": "Edinburgh",
"info": [
{"population": 500000}
]
},
{
"city": "London",
"info": [
{"population": 9000000}
]
}
]
},
{
"country": "Spain",
"columnSpan": 1,
"cities": [
{
"city": "Barcelona",
"info": [
{"population": 15000000}
]
}
]
}
]
},
{
"continent": "Asia",
"columnSpan": 1,
"countries": [
{
"country": "China",
"columnSpan": 1,
"cities": [
{
"city": "Beijing",
"info": [
{"population": 22000000}
]
}
]
}
]
}
];
}
Here is what I have so far for HTML (continents row is easy, struggling with rest):
<div ng-app>
<div class="container-fluid">
<div class="row">
<!-- Player section -->
<div class="col-sm-8" ng-controller="playerCtrl">
<table class="table table-bordered">
<tr>
<th>Continent:</th>
<td ng-repeat="continent in continents" colspan="{{continent.columnSpan}}">{{continent.continent}}</td>
</tr>
<tr>
<th>Country:</th>
<td ng-repeat="country in continents.countries" colspan="{{country.columnSpan}}">{{country.country}}</td>
</tr>
<tr>
<th>City:</th>
<td ng-repeat="city in country.cieties in continents.countries">{{city.city}}</td>
</tr>
<tr>
<th>Population:</th>
<td ng-repeat="city in country.cieties in continents.countries">{{city.info.population}}</td>
</tr>
</table>
</div>
Link to jsfiddle : https://jsfiddle.net/7on62750/
With a little help of a friend I managed to solve this!
solution was to create functions that get me sub-collections.
Feels a bit hacky so feel free to post better solutions.
JS:
function GetCountries(continents) {
var cuntries = [];
for (var i = 0; i < continents.length; i++) {
var a = continents[i];
cuntries = cuntries.concat(a.countries);
}
return cuntries;
}
$scope.GetCountries = function(continents) {
return GetCountries(continents);
}
$scope.GetCities = function(continents) {
var countries = GetCountries(continents);
var cities = [];
for (var i = 0; i < countries.length; i++) {
var a = countries[i];
cities = cities.concat(a.cities);
}
return cities;
}
Html:
<table class="table table-bordered">
<tr>
<th>Continent:</th>
<td ng-repeat="continent in continents" colspan="{{continent.columnSpan}}">{{continent.continent}}</td>
</tr>
<tr>
<th>Country:</th>
<td ng-repeat="country in GetCountries(continents)" colspan="{{country.columnSpan}}">{{country.country}}</td>
</tr>
<tr>
<th>City:</th>
<td ng-repeat="city in GetCities(continents)">{{city.city}}</td>
</tr>
<tr>
<th>Population:</th>
<td ng-repeat="city in GetCities(continents)">{{city.info[0].population}}</td>
</tr>
</table>
jsfiddle: https://jsfiddle.net/2guo5p6d/
Related
I have a nested object JSON file which looks something like this:
"8": {
"age": "Grand Masters",
"gender": "Women",
"division": "Club",
"year_placements": {
"2017": {
"year": 2017,
"event_id": "53522846-5039-11eb-8917-080027315160",
"event_season_id": "d62f237c-5040-11eb-8917-080027315160",
"event_name": "USA Ultimate Masters Championships",
"event_location": "Aurora, Colorado",
"placements": {
"1": {
"d62c24e9-5040-11eb-8917-080027315160": {
"team": "Boston",
"team_location": "Boston, Massachusetts",
"team_season_id": "d62c24e9-5040-11eb-8917-080027315160",
"event_team_placement_id": 5411
}
},
"2": {
"d6333181-5040-11eb-8917-080027315160": {
"team": "J2",
"team_location": "Seattle, Washington",
"team_season_id": "d6333181-5040-11eb-8917-080027315160",
"event_team_placement_id": 5412
}
}
}
},
"2018": {
"year": 2018,
"event_id": "537edbe9-5039-11eb-8917-080027315160",
"event_season_id": "e02569e6-5040-11eb-8917-080027315160",
"event_name": "USA Ultimate Masters Championships",
"event_location": "Aurora, Illinois",
"placements": {
"1": {
"e0227383-5040-11eb-8917-080027315160": {
"team": "Furari",
"team_location": "San Diego, California",
"team_season_id": "e0227383-5040-11eb-8917-080027315160",
"event_team_placement_id": 5852
}
},
"2": {
"e029d38a-5040-11eb-8917-080027315160": {
"team": "Boston",
"team_location": "Boston, Massachusetts",
"team_season_id": "e029d38a-5040-11eb-8917-080027315160",
"event_team_placement_id": 5853
}
}
}
}
}
I have an instance of this object called this.tournament. I'm trying to iterate through each year and display the year, as well as the each team in the placements nested object, all in a single row of a table. Right now my html looks like:
<table>
<thead>
<tr>
<th>Year</th>
<th>Champion</th>
<th>2nd Place</th>
<th>Semi-Finalist</th>
<th>Semi-Finalist</th>
</tr>
</thead>
<tbody>
<tr *ngFor='let year_placement of tournament.year_placements | keyvalue'>
<td>{{year_placement.key}}</td>
<td *ngFor='let team_placement of year_placement.value.placements | keyvalue'>
{{team_placement.key}}
</td>
</tr>
</tbody>
</table>
I have 2 problems that I can see. Most importantly, the year is printed out correctly, but I can't figure out how to print the "team" field. team_placement.key prints out the placement like 1, 2, 3...and team_placement.value just says it [Object, object]. I need team_placement.value.team, but that gives me an undefined.
The 2nd problem I want to always generate 5 total <td>s for each row, even if they have to be empty. Right now if there are less than 4 teams in the "placements" object, it will leave the table missing boxes for those last couple columns. How can I make sure that I always generate 5 's?
You can iterate like below :
<table style="border: solid 1px">
<tr *ngFor='let year of tournament?.year_placements | keyvalue' style="border: solid 1px">
<td style="border: solid 1px">{{year.key}}</td>
<ng-container *ngFor='let teams of year.value.placements | keyvalue'>
<td *ngFor="let team of teams.value | keyvalue" style="border: solid 1px">
<ng-container *ngFor="let teamDesc of team.value | keyvalue">
<div *ngIf="teamDesc.key !== 'team_season_id'">
{{teamDesc.value}}</div>
</ng-container>
</td>
</ng-container>
</tr>
</table>
check this
<table border="$1">
<span *ngFor='let year of data | keyvalue'>
<span *ngIf="year.key == 'year_placements'">
<tr *ngFor='let teams of year.value | keyvalue'>
<td>{{teams.value.year | json}}</td>
<span *ngFor='let item of teams.value.placements | keyvalue'>
<span *ngFor='let subItem of item.value | keyvalue'>
<td>{{subItem.value.team}}</td>
</span>
</span>
</tr>
</span>
</span>
</table>
this is the inherited data that's why
here is example
I have JSON structure like below:
const villages =
{
"lossesOccured":
[
{
"type": "destroyed",
"affectedOn": "humans",
"quantity": 120,
"reliefFund": 100000,
"location": {
"district": "thanjavur",
"villageName": "madukkur",
"pincode": "614903"
}
},
{
"type": "physicalDamage",
"affectedOn": "humans",
"quantity": 250,
"reliefFund": 50000,
"location": {
"district": "thanjavur",
"villageName": "madukkur",
"pincode": "614903"
}
},
]
}
I need help in displaying the JSON data in the form of table like below Using React. Also, need the table row to be added automatically whenever a new element is added in JSON.
<table>
<thead>
<tr>
<th>AffectedOn</th>
<th>Type</th>
<th>Quantity</th>
</tr>
</thead>
<tbody>
{
villages.lossesOccured.map(loss => (
<tr>
<td>{loss.affectedOn}</td>
<td>{loss.type}</td>
<td>{loss.quantity}</td>
</tr>
)
}
</tbody>
</table>
I have a JSON array like this:
[
{
"students": {
"Student1": {
"number": "15",
"books": {
"Mystery": [
"Book1",
"Book2"
]
}
},
"Student2": {
"number": "12",
"books": {
"Romance": [
"Book1"
],
"Adventure": [
"Book1",
"Book2"
]
}
},
"Student3": {
"number": "116",
"books": {
}
}
},
"class": "7th Grade",
"school": "High School 1"
}
]
I want to display this data as a table on an Angular1 page in the following manner:
How can I make it so that the columns resize with each other, and how can I have nested ng-repeats as needed?
I tried to have nested tables inside the student, student-number, and books columns, and a table within the table in the books column, but the alignment was always off, and I couldn't get a default value of "No Books" to show up if the "books" field was empty.
Here's a Plunkr of what I've tried so far.
One of possible solutions is to combine several tables(based on $scope.base, $scope.students, $scope.books arrays, that calculated in controller) into one virtual, desired table via float:left(to ensure they located in one row). Docking of rows is provided by setting of their style:height, which depends on number of their children. Direct solution will be very complicated due to complicated html markup of table with rowspan attributes. Also I added second item(items.push(items[0])), to demonstrate, that solution works at case of several items.
angular.module('app', [])
.controller('MyController', ['$scope', function($scope) {
var items = [
{
"students": {
"Student1": {
"number": "15",
"books": {
"Mystery": [
"Book1",
"Book2"
]
}
},
"Student2": {
"number": "12",
"books": {
"Romance": [
"Book1"
],
"Adventure": [
"Book1",
"Book2"
]
}
},
"Student3": {
"number": "116",
"books": {
}
},
"class": "7th Grade",
"school": "High School 1"
}
}
];
items.push(items[0]);
$scope.base = [];
$scope.students = [];
$scope.books = [];
for(var item of items){
var temp = $scope.books.length;
for(var student in item.students){
if(['class', 'school'].indexOf(student) == -1){
var studentV = item.students[student];
$scope.students.push({name:student, number: studentV.number, w: Object.keys(studentV.books).length || 1});
for(var book in studentV.books)
$scope.books.push((book + ':' + JSON.stringify(studentV.books[book])).replace(/"/g, ''));
if(Object.keys(studentV.books).length == 0)
$scope.books.push('No books');
}
}
$scope.base.push({cl: item.students.class, school: item.students.school, w: $scope.books.length - temp});
}
}]);
table, th, td {
border: 1px solid black;
border-collapse: collapse;
}
table.left, table.left th, table.left td {
border-right: 0px
}
tr {
text-align:center
}
<script src="//code.angularjs.org/snapshot/angular.min.js"></script>
<div ng-app='app' ng-controller="MyController">
<table style='float:left;border-right:0' class='left'>
<thead>
<tr>
<th>School</th>
<th>Class</th>
</tr>
</thead>
<tbody>
<tr ng-repeat='item in base' style='height:{{item.w*30}}px'>
<td>{{item.school}}</td>
<td>{{item.cl}}</td>
</tr>
</tbody>
</table>
<table style='float:left' class='left'>
<thead>
<tr>
<th>Student</th>
<th>Student-number</th>
</tr>
</thead>
<tbody>
<tr ng-repeat='item in students' style='height:{{item.w*30}}px'>
<td>{{item.name}}</td>
<td>{{item.number}}</td>
</tr>
</tbody>
</table>
<table>
<thead>
<tr>
<th>Books</th>
</tr>
</thead>
<tbody>
<tr ng-repeat='item in books track by $index' style='height:30px'>
<td>{{item}}</td>
</tr>
</tbody>
</table>
</div>
I chose to create hidden nested tables to show more information upon click.
I have a REST service, which returns this object:
[
{
"id": 100,
"value": "2452"
},
{
"id": 100,
"value": "2458"
},
{
"id": 1,
"value": "2457"
},
{
"id": 1,
"value": "2459"
},
{
"id": 4,
"value": "2460"
},
{
"id": 5,
"value": "3458"
}
]
Now, using this GET service, I want the following table to be built in angular and show it in UI.
100 1 4 5
-------------------
2452 2457 2460 3458
2458 2459
i.e. the unique ids should create the header and the list of values associates to each header value will be appended to respective column.
I have tried something with ng-repeat like this:
<table border="1">
<tr>
<th ng-repeat="column in cols">{{column.id}}</th>
</tr>
<tr>
<td ng-repeat="column in cols">
<md-list>
<md-list-item class="md-2-line" ng-repeat="val in column.values">
<md-checkbox ng-model="item.done"></md-checkbox>
<div class="md-list-item-text">
??
</div>
</md-list-item>
</md-list>
</td>
</tr>
But still wondering how to do the same? Please help.
Try use groupBy filter.
var app = angular.module('anApp', ['angular.filter']);
app.controller('aCtrl', function($scope) {
$scope.data = [
{
"id": 100,
"value": "2452"
},
{
"id": 100,
"value": "2458"
},
{
"id": 1,
"value": "2457"
},
{
"id": 1,
"value": "2459"
},
{
"id": 4,
"value": "2460"
},
{
"id": 5,
"value": "3458"
}
];
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.22/angular.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/angular-filter/0.4.7/angular-filter.js"></script>
<div ng-app="anApp" ng-controller="aCtrl">
<table border="1">
<tr>
<th ng-repeat="col in data | groupBy: 'id'">{{col[0].id}}</th>
</tr>
<tbody>
<tr>
<td ng-repeat="col in data | groupBy: 'id'">
<table>
<tr ng-repeat="c in col">
<td> {{c.value}}</td>
</tr>
</table>
</td>
</tr>
</tbody>
</table>
</div>
I have an angular app where i am trying to create a table from a json. My json is as follows:
[
{
"campus_id": "321",
"name": "0"
},
{
"campus_id": "231",
"name": "1"
},
{
"campus_id": "123",
"name": "2"
}
]
Generally we will create a table in the html as follows:
<table class="table table-striped">
<tr>
<th>
Campus id
</th>
<th>
Name
</th>
</tr>
<tr ng-repeat="item in items">
<td >
{{item.campus_id}}
</td>
<td >
{{item.name}}
</td>
</tr>
</table>
How do i create even the headers from the json instead of defining them ourselves?
I would add the column headers within the json result like so
columnDefs: [
{field: 'campus_id', displayName: 'Campus ID'},
{field: 'name', displayName: 'Name'}],
data:
[
{
"campus_id": "57911000",
"name": "0"
},
{
"campus_id": "57911001",
"name": "HIGHLAND PARK HIGH SCHOOL"
},
{
"campus_id": "57911007",
"name": "P A S S Learning Center School"
}
]
otherwise you could use the key, value pairing ng-repeat="(key,value) in items" with a filter to return 1 row and then use {{key}}