How to make expandable table rows within an ngFor loop [Angular]? - javascript

I've nested tables, when a row is clicked I need to display data underneath the table row. However, the data is being displayed at the end of ngRepeat.
HTML:
<table class="table table-hover table-bordered table-responsive-xl">
<thead>
<th> Name </th>
<th> Place </th>
<th> Phone </th>
</thead>
<tbody>
<tr *ngFor="let data of data1" (click) ="expand()">
<td> +{{data.name}} </td>
<td> {{data.place}} </td>
<td> {{data.phone}} </td>
<td> {{data.hobbies}} </td>
<td> {{data.profession}} </td>
</tr>
<ng-container *ngIf="expandContent">
<tr *ngFor="let data of data2">
<td> {{data.datades.name}} </td>
<td> {{data.datades.hobbies}} </td>
<td> {{data.datades.profession}} </td>
</tr>
</ng-container>
</tbody>
</table>
Component :
export class AppComponent {
expandContent = true;
data1 =[{
'name' : 'john',
'place' : 'forest',
'phone' : '124-896-8963'
},{
'name' : 'Jay',
'place' : 'City',
'phone' : '124-896-1234'
}, {
'name' : 'Joseph',
'place' : 'sky',
'phone' : '124-896-9632'
},
]
data2 =[{
'whoseData' : 'john',
'datades' : {
'name' : 'john',
'hobbies' : 'singing',
'profession' : 'singer'
}
},{
'whoseData' : 'Jay',
'datades' : {
'name' : 'jay',
'hobbies' : 'coding',
'profession' : 'coder'
}
}
]
expand(){
this.expandContent = !this.expandContent
}
}
When the first row is clicked I would like to display, the data associated with the first row, under it.
Expected result
DEMO

You would need to make these changes:
Include the main row and the corresponding detail rows in the same ngFor loop iteration
Add an expanded property to the data objects, instead of having the global expandContent
Define a method to filter the details of the clicked row
The template could look as follows:
<ng-container *ngFor="let data of data1">
<tr (click)="data.expanded = !data.expanded">
<td> {{ data.expanded ? '–' : '+'}} {{data.name}} </td>
<td> {{data.place}} </td>
<td> {{data.phone}} </td>
<td> {{data.hobbies}} </td>
<td> {{data.profession}} </td>
</tr>
<ng-container *ngIf="data.expanded">
<tr *ngFor="let details of findDetails(data)">
<td> {{details.datades.name}} </td>
<td> {{details.datades.hobbies}} </td>
<td> {{details.datades.profession}} </td>
</tr>
</ng-container>
</ng-container>
where findDetails is defined as:
findDetails(data) {
return this.data2.filter(x => x.whoseData === data.name);
}
See this stackblitz for a demo.

Your dropdown data is being displayed at the bottom of the table because your ng-container is in a separate div. Checkout Bootstrap Collapse and look at the Accordion example to see if it will solve your problem: https://getbootstrap.com/docs/4.1/components/collapse/

Related

Adjust HTML table with content want to displayed, Angular

My page is about showing data table from user on shift indicator.
My dashboard.component.html
<table class="table">
<thead>
<tr>
<th *ngFor="let col of tablePresetColumns">
{{col.content}}
</th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
<tr *ngFor="let row of tablePresetData ">
<td *ngFor="let cell of row"> {{cell.content}}</td>
<td *ngFor="let cell of row">
<span class ="dot" [ngClass]="{
'dot-yellow' : cell.content == 'Busy',
'dot-green' : cell.content == 'Idle',
'dot-red' : cell.content == 'Overload'}">
</span>
</td>
</tr>
</tbody>
</table>
My example data :
tablePresetColumns = [{ id: 1, content: "Username" }];
tablePresetData = [
[{ id: 1, content: "Adiet Adiet" }, { id: 2, content: "Idle" }],
[{ id: 1, content: "Andri Irawan" }, { id: 2, content: "Idle" }],
[{ id: 1, content: "Ari Prabudi" }, { id: 2, content: "Idle" }]
];
How should i do to :
removes the status in the page that I want to display, so it just
appear username and color indicator
I've tried to change *ngFor into this (with index 1) :
<td *ngFor="let cell of row"> {{cell.content[1]}}
but it didn't works at all
Try
<td> {{row[0].content}}</td>
instead of
<td *ngFor="let cell of row"> {{cell.content[1]}}
How about this
<table class="table">
<thead>
<tr>
<th *ngFor="let col of tablePresetColumns">{{col.content}}</th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
<tr *ngFor="let row of tablePresetData">
<ng-container *ngFor="let cell of row, let i = index">
<td *ngIf="i == 0">{{cell.content}}</td>
<td *ngIf="i == 0">
<span
[ngClass]="{
'dot-yellow' : row[1].content == 'Busy',
'dot-green' : row[1].content == 'Idle',
'dot-red' : row[1].content == 'Overload'}"
>
</span>
</td>
</ng-container>
</tr>
</tbody>
</table>
See here for a live example: https://codesandbox.io/s/7y2r69992j
Note
I think your data structure is a but awkward and un-semantic. It would be better, if your data would look like this:
tablePresetColumns = ["Username", "Status"];
tablePresetData = [
{username: "Adiet Adiet", status: "Idle"},
{username: "Andri Irawan", status: "Busy" },
{username: "Ari Prabudi", status: "Overload" }
];
So you could show the table like this
<table class="table">
<thead>
<tr>
<th *ngFor="let col of tablePresetColumns">{{col}}</th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
<tr *ngFor="let row of tablePresetData">
<td>{{ row.username }}</td>
<td>
<span [ngClass]="{
'dot-yellow' : row.status == 'Busy',
'dot-green' : row.status == 'Idle',
'dot-red' : row.status == 'Overload'
}">
</span>
</td>
</tr>
</tbody>
</table>
Much easier to read and maintain.
Also a live example: https://codesandbox.io/s/o27pv052z
You need to use .map on tablePresetData and have some changes on object structure
angular code here:
tablePresetColumns: any = [
{thTitle:"id", thWidth:'30px'},
{thTitle:"Username", thWidth:'160px'},
{thTitle:"Status", thWidth:'100px'},
{thTitle:"", thWidth:'60px'}
];
tablePresetData: any = [
{ id: 1, Username: "Adiet Adiet", status: "Idle" },
{ id: 2, Username: "Andri Irawan", status: "Overload" },
{ id: 3, Username: "Ari Prabudi", status: "Busy" }
];
constructor() {}
ngOnInit() {
this.tablePresetData.map((item: any) => {
if (item.status === "Busy") {
item["className"] = "dot-yellow";
}
if (item.status === "Idle") {
item["className"] = "dot-green";
}
if (item.status === "Overload") {
item["className"] = "dot-red";
}
});
console.log("this.tablePresetData", this.tablePresetData);
}
Html code
<table>
<thead>
<tr>
<th
*ngFor="let tableHd of tablePresetColumns"
[width]="tableHd.thWidth" >
{{tableHd.thTitle}}
</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let tableCol of tablePresetData">
<td>{{tableCol.id}}</td>
<td>{{tableCol.Username}}</td>
<td>{{tableCol.status}}</td>
<td>
<span [ngClass]='tableCol.className' class="circle"></span>
</td>
</tr>
</tbody>
</table>
CSS Class -
.circle{border-radius: 10px; display: inline-block; height: 10px; width: 10px; }
.dot-yellow{background-color: yellow;}
.dot-green{background-color:green;}
.dot-red{background-color:red;}

Can you populate a table with Angular.js without hardcoding column names?

I have a simple Angular.js application that grabs tabular data from a mysql database and shows it in a simple bootstrap table. I’m using this code below to show the table column names without hardcoding them individually…
HTML:
<table class="table">
<thead>
<tr style="background:lightgrey">
<th ng-repeat="column in columns"> {{ column }} </th>
</tr>
</thead>
and in the controller I create ’$scope.columns’ with something like this…
var columnNames = function(dat) {
var columns = Object.keys(dat[0]).filter(function(key) {
if (dat[0].hasOwnProperty(key) && typeof key == 'string') {
return key;
}
});
return columns;
};
DataFactory.getTables(function(data) {
$scope.columns = columnNames(data);
$scope.tables = data;
});
And this works as expected and it’s great, but what about the the rest of the data.. So for example, the body of my table currently looks like this…
HTML:
<tbody>
<tr ng-repeat="x in tables ">
<td> {{ x.id}} </td>
<td> {{ x.name }} </td>
<td> {{ x.email }} </td>
<td> {{ x.company }} </td>
</tbody>
I’ve tried using two loops like this…
HTML:
<tbody>
<tr ng-repeat="x in tables">
<td ng-repeat=“column in columns”> {{ x.column }} </td>
</tr>
</tbody>
But this code doesn’t work, So is it possible to populate a table with angular without hardcoding the column names in HTML, and if so whats the most efficient way to do so?
You might want to try this https://jsfiddle.net/8w2sbs6L/.
<div data-ng-app="APP">
<table ng-controller="myController" border=1>
<thead>
<tr>
<td ng-repeat="column in columns">{{column}}</td>
</tr>
</thead>
<tbody>
<tr ng-repeat="x in tables">
<td ng-repeat="column in columns">{{x[column]}}</td>
</tr>
</tbody>
</table>
</div>
<script>
'use strict';
angular.module('APP', [])
.controller('myController', ['$scope', function($scope){
$scope.tables = [
{
"column1":"row1-column1",
"column2":"row1-column2",
"column3":"row1-column3",
"column4":"row1-column4"
},
{
"column1":"row2-column1",
"column2":"row2-column2",
"column3":"row2-column3",
"column4":"row2-column4"
}
];
$scope.columns = [
"column1",
"column2",
"column3",
"column4"
];
}]);
</script>

add multiple rows in one column using angular ng-repeat

I want to generate table contents using json object. I am using ng-repeat to insert multiple rows in a table. But I have to generate table like the following.
--------------
ID | subjects
--------------
| S1
1 | S2
| S3
--------------
| S4
2 | S5
| S6
--------------
my angular code is:
<tr ng-repeat = "user in users">
<td>{{user.id}}</td>
<td>{{user.subject}}</td>
</tr>
my json object is :
user:[
{id:1 ,
subjects:[
{id:1 , name:"eng"}
{id:2 , name:"phy"}
]
},
{id:2 ,
subjects:[
{id:1 , name:"eng"}
{id:3 , name:"math"}
]
}
]
I want to generate html table like this
<table>
<tr>
<td >ID</td>
<td>Sub</td>
</tr>
<tr>
<td rowspan="3">1</td>
<td>S1</td>
</tr>
<tr>
<td>S2</td>
</tr>
<tr>
<td>S3</td>
</tr>
how to insert multiple rows in one column using angular
Use ng-repeat-start and ng-repeat-end. For example:
<tr ng-repeat-start="user in users">
<td rowspan="{{user.subjects.length+1}}">{{user.id}}</td>
</tr>
<tr ng-repeat-end ng-repeat="subject in user.subjects">
<td>S{{subject.id}}</td>
</tr>
Here is a full example:
var app = angular.module('MyApp', []);
app.controller('MyController', function ($scope) {
var users = [{
id: 1,
subjects: [{
id: 1,
name: "eng"
}, {
id: 2,
name: "phy"
}]
}, {
id: 2,
subjects: [{
id: 1,
name: "eng"
}, {
id: 3,
name: "math"
}, {
id: 4,
name: "hist"
},
{
id: 5,
name: "geog"
}]
}];
$scope.users = users;
});
table { border-collapse: collapse; }
td { border: 1px solid Black; }
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<table ng-app="MyApp" ng-controller="MyController">
<thead>
<tr>
<td>ID</td>
<td>Subjects</td>
</tr>
</thead>
<tbody>
<tr ng-repeat-start="user in users">
<td rowspan="{{user.subjects.length+1}}">{{user.id}}</td>
</tr>
<tr ng-repeat-end ng-repeat="subject in user.subjects">
<td>S{{subject.id}}</td>
</tr>
</tbody>
</table>
Also, working fiddle here: http://jsfiddle.net/donal/r51d5fw5/17/
An alternative version, using nested ng-repeat, can be implemented using a div to display the nested subject information:
<tr ng-repeat="user in users">
<td>{{user.id}}</td>
<td>
<div ng-repeat="subject in user.subjects">S{{subject.id}}</div>
</td>
</tr>
rowspan will do everything you need. Follow this link:
w3schools This is one of the best resources for web development.
Using div u can also do
<div ng-repeat = "user in users">
<div> {{user.id}} </div>
<div ng-repeat = "user1 in users.subjects">
{{user1.id}} : {{user1.name}}
<div>
</div>
Donal's answer is good.
But I edited to show beautiful table:
<table class="table table-bordered table-hover table-height m-b-xs">
<thead>
<tr>
<td>ID</td>
<td>Subjects</td>
<td>name</td>
</tr>
</thead>
<tbody>
<tr ng-repeat-start="user in users">
<td rowspan="{{user.subjects.length}}">key {{user.id}}</td>
<td>S{{ user.subjects[0].id }}</td>
<td>{{ user.subjects[0].name }}</td>
</tr>
<tr ng-repeat-end ng-repeat="subject in user.subjects.slice(1)">
<td>S{{subject.id}}</td>
<td>{{subject.name}}</td>
</tr>
</tbody>

Generate html table using angular

I want to generate html table using angular.I have a json object and i used ng-repeat to add multiple rows. But my table structure is different.
I want to generate table structure like this:
<table>
<tr>
<td >ID</td>
<td>Sub</td>
</tr>
<tr>
<td rowspan="3">1</td>
<td>S1</td>
</tr>
<tr>
<td>S2</td>
</tr>
<tr>
<td>S3</td>
</tr>
</table>
--------------
ID | subjects
--------------
| S1
--------
1 | S2
--------
| S3
--------------
| S4
--------
2 | S5
--------
| S6
--------------
user:[
{id:1 ,
subjects:[
{id:1 , name:"eng"}
{id:2 , name:"phy"}
]
},
{ id:2 ,
subjects:[
{id:1 , name:"eng"}
{id:3 , name:"math"}
]
}
]
my angular code is:
<tr ng-repeat = "user in users">
<td>{{user.id}}</td>
<td>{{user.subject}}</td>
</tr>
I want to know how to generate table structure like above
You need to use ng-repeat-start and ng-repeat-end. For example:
var app = angular.module('MyApp', []);
app.controller('MyController', function ($scope) {
var users = [{
id: 1,
subjects: [{
id: 1,
name: "eng"
}, {
id: 2,
name: "phy"
}]
}, {
id: 2,
subjects: [{
id: 1,
name: "eng"
}, {
id: 3,
name: "math"
}]
}];
$scope.users = users;
});
table { border-collapse: collapse; }
td { border: 1px solid Black; }
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<table ng-app="MyApp" ng-controller="MyController">
<thead>
<tr>
<td>ID</td>
<td>Subjects</td>
</tr>
</thead>
<tbody>
<tr ng-repeat-start="user in users">
<td rowspan="{{user.subjects.length+1}}">{{user.id}}</td>
</tr>
<tr ng-repeat-end ng-repeat="subject in user.subjects">
<td>S{{subject.id}}</td>
</tr>
</tbody>
</table>
Also, working fiddle here: http://jsfiddle.net/donal/r51d5fw5/17/
Similar to the nested structure of your object, you can nest your ng-repeats like this...
<tr ng-repeat = "user in users">
<td>{{user.id}}</td>
<td ng-repeat="subject in user.subjects">{{subject.name}}</td>
</tr>
I split your JSON and push it into two $scope variable, like the below:
angular.forEach($scope.user, function(user) {
$scope.userDetails.push({
userId: user.id,
});
angular.forEach(user.subjects, function(subject) {
$scope.subjectDetails.push({
userId: user.id,
subjectName: subject.name
});
});
});
In the HTML, I am using filter to filter by user's id.
<table>
<thead>
<tr>
<th style="width: 50px">ID</th>
<th style="width: 75px">Subjects</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="user in userDetails">
<td><span ng-bind="user.userId"></span>
</td>
<td>
<table>
<tr ng-repeat="sub in subjectDetails | filter: {userId: user.userId}">
<td>
<div ng-bind="sub.subjectName"></div>
</td>
</tr>
</table>
</td>
</tr>
</tbody>
</table>
This is also one of the way to achieve this.
Sample Plunker
Here, I'm assuming that you want each user in users (in your JSON object) in one table, so you can do something as follows:
<table ng-repeat="user in users">
<tr>
<td>{{user.id}}</td>
<td>Subjects</td>
</tr>
<tr ng-repeat="subject in user.subjects">
<td>{{subject.id}}</td>
<td>{{subject.name}}</td>
</tr>
</table>
Adjust the html accordingly based on your needs, but this is the basic idea :)
Hope this helps!
add users object in $scope.
$scope.users=[
{id:1 ,
subjects:[
{id:1 , name:"eng"}
{id:2 , name:"phy"}
]
},
{ id:2 ,
subjects:[
{id:1 , name:"eng"}
{id:3 , name:"math"}
]
}
]
Here is the html.
<table border="1">
<tr>
<th> ID </th>
<th> subjects </th>
</tr>
<tr ng-repeat="user in users">
<td>{{user.id}}</td>
<td><table>
<tr ng-repeat="subject in user.subjects">
<td>{{subject.name}}</td>
</tr>
</table></td>
</tr>
</table>
Here is the plunker

nested arrays with ng-repeat and table html

I want to take this json place it into a HTML table.
"columns" : [
{
"id" : 0,
"column_name" : "Column 1",
"cards" : [
{
"id" : 0,
"task" : "Task 1"
},
{
"id" : 1,
"task" : "Task 2"
}
]
},
{
"id" : 1,
"column_name" : "Column 2",
"cards" : [
{
"id" : 0,
"task" : "Task 3"
}
]
}]
I have done quite a bit of searching on SO and cannot find why it is not doing what I expect.
https://jsfiddle.net/6nh100ca/9/
This is what I am expecting.
**Column 1 | Column 2**
Task 1 | Task 3
Task 2 |
https://stackoverflow.com/a/20063394/3279550
http://www.bennadel.com/blog/2456-grouping-nested-ngrepeat-lists-in-angularjs.htm
https://stackoverflow.com/a/26607425/3279550
This is what I have
<table >
<thead >
<tr>
<th ng-repeat="column in entity.columns">{{column.column_name}}</th>
</tr>
</thead>
<tbody ng-repeat="column in entity.columns" >
<tr ng-repeat="card in column.cards">
<td >{{card.task}}</td>
</tr>
</tbody>
</table>
If you want to stick with creating your own <table> manually, you need to pre-process your data object in order to fit the row logic. Try something like this fiddle:
Add this in your controller:
$scope.rowColumns = [];
$scope.columns.forEach(function(column, columnIndex){
column.cards.forEach(function (card, rowIndex){
if (!$scope.rowColumns[rowIndex])
$scope.rowColumns[rowIndex] = [];
$scope.rowColumns[rowIndex][columnIndex] = card;
});
});
console.log($scope.rowColumns);
Then add this in your html:
<tr ng-repeat="row in rowColumns">
<td ng-repeat="cell in row">
{{cell.task}}
</td>
</tr>
column.columnName should be column.column_name as per your example data, there after you could have two ng-repeat over a data where you will be actually have 1st ng-repeat over tbody & then the another will appear on tr. I'd prefer this approach when I have small data set. For larger data set the answer given by #Tiago is fine.
<table >
<thead >
<tr>
<th ng-repeat="column in entity.columns">{{column.columnName}}</th>
</tr>
</thead>
<tbody ng-repeat="column in entity.columns" >
<tr ng-repeat="card in column.cards">
<td >{{card.task}}</td>
</tr>
</tbody>
</table>

Categories

Resources