I have the following array in my module in Angular.js:
$scope.hsbody = []; //Data array
$scope.hsresult = []; //Data array
$scope.hsProcess = []; //Boolean array
$scope.hssuccess = []; //Boolean array
$scope.hsfailure = []; //Boolean array
$scope.hsExpand = []; //Boolean array
$scope.hsExpandUser = []; //Boolean array
I want to show the array items in my Html page:
hsresult
hsbody
hsresult
hsbody
and so on..
So I do the following:
<div>
<pre>
<table class="table table-condensed">
<tr ng-repeat="hs in hsbody track by $i" ng-show="hsProcess[i] && !hssuccess[i] && !hsfailure[i]" class="warning"><td><div class="glyphicon"></div>{{hsbody}}</td></tr>
<tr ng-show="hssuccess" ng-repeat="highstate in hsbody track by $i" class="success"><td><div class="glyphicon" ng-show="!hsExpand[i]"></div><div class="glyphicon" ng-show="hsExpand[i]"></div>{{ hsresult[i] }} </td></tr>
<tr ng-show="hsfailure" ng-repeat="hs in hsbody track by $i" class="danger"><td><div class="glyphicon" ng-show="!hsExpand"></div><div class="glyphicon" ng-show="hsExpand[i]"></div>{{ hsresult[i] }}</td></tr>
<tr ng-repeat="hs in hsbody track by $i" ng-show="(hsProcess[i] && hsExpand[i]) || (hsExpand[i] && hsfailure[i])" class="active"><td><pre>{{ hsbody[i] }}</pre></td></tr>
</table>
</pre>
</div>
The problem is that nothing is shown in my HTML. but when I get rid of the ng-repeat and use i=0, then I can see the values.
It seems that I don't use the ng-repeat correctly, but I don't know where I wrong.
Inside anything with 'ng-repeat' you'll have to reference everything through whatever you specified in the ng-repeat.
e.g. say you had an array, 'main', in the controller 'data'.
You have usernames in objects within data.main
$scope.main = [
{username: 'jeff'},
{username: 'brad'},
]
or
this.main = [
{username: 'jeff'},
{username: 'brad'},
]
If you wrote
<div ng-repeat="theData in data.main track by $i">
{{ data.main.username }}
</div>
an error would come up, because it's undefined.
If you wrote
<div ng-repeat="theData in data.main track by $i">
{{ theData.username }}
</div>
you would get what you wanted.
The reason is that you are specifying theData as the source of everything inside the ng-repeat.
theData is equivalent to data.main, for inside the ng-repeat
You can't access anything outside the object data.main inside the div.
If you need anything from outside, think again. Do you really want that data printed however many times?
if you want to use the "track by" with index, you should write there: "track by $index".
good luck!
this works for you?
<div>
<pre>
<table class="table table-condensed">
<tr ng-repeat="hs in hsbody track by $index" ng-show="hsProcess[$index] && !hssuccess[$index] && !hsfailure[$index]" class="warning">
<td>
<div class="glyphicon"></div>{{hs}}
</td>
</tr>
<tr ng-show="hssuccess" ng-repeat="highstate in hsbody track by $index" class="success">
<td>
<div class="glyphicon" ng-show="!hsExpand[i]"></div>
<div class="glyphicon" ng-show="hsExpand[$index]"></div>{{ hsresult[$index] }}
</td>
</tr>
<tr ng-show="hsfailure" ng-repeat="hs in hsbody track by $index" class="danger">
<td>
<div class="glyphicon" ng-show="!hsExpand"></div>
<div class="glyphicon" ng-show="hsExpand[i]"></div>{{ hsresult[$index] }}
</td>
</tr>
<tr ng-repeat="hs in hsbody track by $index" ng-show="(hsProcess[$index] && hsExpand[$index]) || (hsExpand[$index] && hsfailure[$index])" class="active">
<td>
<pre>{{ hsbody[$index] }}</pre>
</td>
</tr>
</table>
</pre>
</div>
Related
My code is quite simple. I only want to add John and Marie to my table.
Works great but my issue is if there is no John and Marie I want to create a row and show a - in my td.
How do I know if there was not added any row when the ng-repeat ends?
<tr class="text-center" ng-if="name == 'John' || name == 'Marie'" ng-repeat="name in vm.names track by $index">
<td>{{name}}</td>
</tr>
Use the ng-switch directive:
<tr class="text-center" ng-switch"name" ng-repeat="name in vm.names track by $index">
<td ng-switch-when="John">{{name}}</td>
<td ng-switch-when="Marie">{{name}}</td>
<td ng-switch-when="Paul">{{name}}</td>
<td ng-switch-default>-</td>
</tr>
You could map your original object in the controller with something like this:
this.names = this.names.map(name => {
name ? name : '-';
})
I am completely new to angular, I need to create a table. The data array is as-follows:-
data = [{rollno: 1,name: 'abc',subject: 'maths'},
{rollno: 4,name: 'xyz',subject: 'history'},
{rollno: 2,name: 'pqr',subject: 'history'}
];
I want to create a table with some summary rows based on this data and then when I click the expand button the sub-rows should appear beneath that summary-row indicating the actual data.
For example:-
Expand/Collapse | No of Students | Subject
click here 1 Maths
click here 2 History
When I toggle the expand/collapse button on the second row for example I want actual rows to appear like this beneath it:-
Expand/Collapse | No of Students | Subject
click here 1 Maths
click here 2 History
RollNo | StudentName
4 xyz
2 pqr
How Can I achieve this?
1) Grouping the data by subject
First you need to group the data by subject and then count the items in each group.
You can use the angular.filter module's groupBy filter to do this.
1a) Add a dependency on that module as follows:
var app = angular.module("yourModuleName", ["angular.filter"]);
1b) You can then use the groupBy filter in an ng-repeat directive on a <tbody> tag like this:
<tbody ng-repeat="(key, value) in data | groupBy: 'subject'">
1c) You're now dealing with the data in the format below. This is an object of key/value pairs where "maths" and "history" are both keys, and the arrays are the values
{
"maths": [
{
"rollno": 1,
"name": "abc",
"subject": "maths",
}
],
"history": [
{
"rollno": 4,
"name": "xyz",
"subject": "history",
},
{
"rollno": 2,
"name": "pqr",
"subject": "history",
}
]
}
2) Displaying the grouped data and counting the items in each group
Use key and value to display the grouped data in a table as follows:
<table>
<thead>
<tr>
<th>Subject</th>
<th>Number of Students</th>
<th>Expand/Collapse</th>
</tr>
</thead>
<tbody ng-repeat="(key, value) in data | groupBy: 'subject'">
<tr>
<td>{{ key }}</td>
<td>{{ value.length }}</td>
<td>
<button>
Expand/Collapse
</button>
</td>
</tr>
<tr>
<td colspan="3">
<table>
<thead>
<tr>
<th>Roll Number</th>
<th>Name</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="student in value">
<td>{{ student.rollno }}</td>
<td>{{ student.name }}</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
Note the extra <tr> and nested table with another ng-repeat for displaying the student data. Currently all nested student data will display, the next step is to conditionally show/hide the nested tables based on which expand/collapse button was clicked.
3) Showing/Hiding the nested student data
3a) Add an ng-click directive on the button so that it passes in the key to an onExpandClicked function on your controller:
<button ng-click="onExpandClicked(key)">
Expand/Collapse
</button>
3b) Create the onExpandClicked function in your controller:
$scope.onExpandClicked = function(name){
$scope.expanded = ($scope.expanded !== name) ? name : "";
}
This sets a value on the $scope that can be used in the view to decide whether to show/hide a section of student data. The key is passed into the function as the name parameter and $scope.expanded will either be set to name or reset to "" depending on whether the passed in name is the same as the current $scope.expanded value or not.
3c) Finally, use the $scope.expanded variable in an ng-if directive on the second <tr> tag of <tbody> to show or hide the nested student data:
<table>
<thead>
<tr>
<!-- Omitted for brevity -->
</tr>
</thead>
<tbody ng-repeat="(key, value) in data | groupBy: 'subject'">
<tr>
<!-- Omitted for brevity -->
</tr>
<tr ng-if="expanded === key">
<!--
Omitted for brevity
-->
</tr>
</tbody>
</table>
Demo
CodePen: How to show/hide grouped data created by the angular.filter module's groupBy filter
Design a table with html and iterate through your data object with ng-repeat loop to display the data.
ngRepeat
W3Schools has some basic examples on how to display tables with AngularJS
Angular Tables
First you should replace the actual table by a div structure, because it is not possible to mix two kinds of table like you are planning (when I get you right).
You could toggle every row with a ng-click with the corresponding expanded content like this (pseudo code, I hope the idea gets clear):
<div class="row-header">
<span>RollNo</span>
<span>StudentName</span>
</div>
<div class="row-content" ng-if="!row_4_expanded" ng-click="row_4_expanded = !row_4_expanded">
<span>4</span>
<span>xyz</span>
</div>
<div ng-if="row_4_expanded">
<div class="row-expanded-header">
<span>No of Students</span>
<span>Subject</span>
</div>
<div class="row-expanded-content">
<span>1</span>
<span>Math</span>
</div>
<div class="row-expanded-content">
<span>2</span>
<span>History</span>
</div>
</div>
<div class="row-content" ng-if="!row_2_expanded" ng-if="row_2_expanded" ng-click="row_2_expanded = !row_2_expanded">
<span>2</span>
<span>pqr</span>
</div>
<div ng-if="row_2_expanded">
<div class="row-expanded-header">
<span>No of Students</span>
<span>Subject</span>
</div>
<div class="row-expanded-content">
<span>1</span>
<span>Math</span>
</div>
<div class="row-expanded-content">
<span>2</span>
<span>History</span>
</div>
</div>
When you now click on a row, it toggle presens with the corresponding expanded one.
Here is a working example which resolves your problem.
var indexCtrl = ['$scope', function($scope){
$scope.num = 0;
$scope.test = [{rollno: 1,name: 'abc',subject: 'maths'},
{rollno: 4,name: 'xyz',subject: 'history'},
{rollno: 2,name: 'pqr',subject: 'history'}
];
$scope.changeShow = function(index){
$scope.num = index;
};
}];
<!DOCTYPE html>
<html ng-app>
<head>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.26/angular.min.js"></script>
<meta charset="utf-8">
<title>JS Bin</title>
</head>
<body ng-controller='indexCtrl'>
<table>
<tr>
<td>Expand/Collapse</td>
<td>No of Students</td>
<td>Subject</td>
</tr>
<tr ng-repeat='i in test' ng-class="num == $index ? red : none">{{}}
<td ng-click='changeShow($index)'>click here</td>
<td>{{$index +1}}</td>
<td >{{i.subject}}</td>
</tr>
</table>
<table>
<tr>
<td>RollNo</td>
<td>StudentName</td>
</tr>
<tr ng-repeat='i in test'>
<td ng-show='num == $index'>{{i.rollno}}</td>
<td ng-show='num == $index'>{{i.name}}</td>
</tr>
</table>
<style>
table tr td{
border: 1px solid black
}
</style>
</body>
</html>
Hope it helps you.
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>
localStorage is an object where the multi-dimensional array I want to iterate on (localStorage.add) is stored along with other arrays.
<tr ng-repeat = "(key, value) in localStorage track by $index" ng-if = "localStorage.add.length > $index || localStorage.subject.length > $index || localStorage.emailContent > $index" >
<td>
<input type="checkbox" ng-checked="checkAllEmail" ng-model="selectedEmail"/>
<a href="#">
<span class="glyphicon glyphicon-star-empty"></span>
</a>
</td>
<td >
{{localStorage.add[$index]}}
<td>
<td >
{{localStorage.subject[$index]}}
<td>
<td >
{{localStorage.emailContent[$index]}}
<td>
</tr>
This is the localStorage.add array - [["Elizabeth","Caroline"],["Patricia"],["Madhu"]].
{{localStorage.add[$index]}} displays
["Elizabeth","Caroline"]
["Patricia"]
["Madhu"]
I want only the values within the array to be displayed. So, for example, {{localStorage.add[1][0]}} displays "Patricia" and not ["Patricia"]. Does anyone have ideas on how to implement this? I tried {{localStorage.add[$index][$index]}}, it displays only Elizabeth ({{localStorage.add[0][0]}}) and not ["Elizabeth"]. So, I am looking for something similar to {{localStorage.add[$index][$index]}} that works for all the elements in the array.
Just to avoid confusion, my app is working as desired. I just don't want the user to see that I am storing these values in an array. This is what the final output should look like:
Elizabeth,Caroline
Patricia
Madhu
You need to convert the array to string, so in your controller, make a function that your view can call and get a returned string, such as:
<tr ng-repeat = "(key, value) in localStorage track by $index" ng-if = "localStorage.add.length > $index || localStorage.subject.length > $index || localStorage.emailContent > $index" >
<td>
<input type="checkbox" ng-checked="checkAllEmail" ng-model="selectedEmail"/>
<a href="#">
<span class="glyphicon glyphicon-star-empty"></span>
</a>
</td>
<td>
{{getNames(localStorage.add[$index])}}
<td>
<td >
{{localStorage.subject[$index]}}
<td>
<td >
{{localStorage.emailContent[$index]}}
<td>
</tr>
This will be in your controller, and you can alter delimiter as needed
$scope.getNames = function(names){
return names.join(',')
}
You could probably do this directly in the view like this:
localStorage.add[$index].join(',')
but I don't recommend it, if it works (not sure)
I have a list of items of different types and I would like to display them in a table.
The items of one type will have two columns and items of another type just one. Any suggestions how to change conditionally the colspan on the <> tag on fly?
<div ng-init="items = [
{name:'item1', old:1, new:2},
{name:'item2', old:2, new:2},
{name:'item3', msg: 'message'},
{name:'item4', old:0, new:2}
]">
<table border=1>
<tr ng-repeat="item in items" >
<th>{{item.name}}</th>
<td>{{item.old}}</td>
<td colspan='2'>{{item.msg}}</td>
<td>{{item.new}}</td>
</tr>
</table>
Here is the example to play in jsfiddle: http://jsfiddle.net/38LXt/1/
Thanks!
You can use conditional directives, such as ng-show, to do something like this:
<table border=1>
<tr ng-repeat="item in items" >
<th>{{item.name}}</th>
<td>{{item.old}}</td>
<td colspan="2" ng-show="item.type == 'typeA'">{{item.msg}}</td>
<td ng-show="item.type == 'typeB'">{{item.msgB1}}</td>
<td ng-show="item.type == 'typeB'">{{item.msgB2}}</td>
<td>{{item.new}}</td>
</tr>
</table>
More info about ng-show:
ngShow directive