I want to loop through a two-dimensional structure in angularjs to display it in a table. The data looks as follows:
data = {
"keyA": ["valueA", "valueB"],
"keyB": ["valueC", "valueD"]
}
the output should look like this:
<table>
<tr>
<th>keyA</th>
<td>valueA</td>
</tr>
<tr>
<th>keyA</th>
<td>valueB</td>
</tr>
<tr>
<th>keyB</th>
<td>valueC</td>
</tr>
<tr>
<th>keyB</th>
<td>valueD</td>
</tr>
</table>
at the moment my angular enriched html doesn't work and looks as follows:
<table>
<div ng:repeat="(key, values) in data">
<div ng:repeat="value in values">
<tr>
<td>{{key}}</td>
<td>{{value}}</td>
</tr>
</div>
</div>
</table>
In this case I'm using the <div> element, but it doesn't work because obviously a <div> doesn't belong into a <table> like that. Is there some find of a No-Op-Element, which I have to use for loops like this?
I'm not sure if that's possible. Maybe someone can be a little more creative then I. You could try something like this though:
Controller-
var data = {
"keyA": ["valueA", "valueB"],
"keyB": ["valueC", "valueD"]
};
$scope.getPairs = function() {
var ret = [];
for(var key in data) {
for(var i = 0; i < data[key].length; i++) {
ret.push(key, data[key][i]);
}
}
return ret;
}
HTML -
<table>
<tr ng-repeat="pair in getPairs() track by $index">
<td>{{pair[0]}}</td>
<td>{{pair[1]}}</td>
</tr>
</table>
You could add ngRepeat on <tr> and <tbody> element:
<table>
<tbody ng-repeat="(key, values) in data">
<tr ng-repeat="value in values">
<th>{{key}}</th>
<td>{{value}}</td>
</tr>
</tbody>
</table>
Plunker
Related
Using pure javascript
My code
<div id="all-items">
<table>
<tbody>
<tr title="Text 1"></tr>
<tr title="Text 2"></tr>
<tr title="Text 3"></tr>
</tbody>
</table>
</div>
I know with jQuery I can use
$("#all-items table tbody tr").title
will return
"Text 1"
but jQuery isn't working with my front end framework I'm using for some reason. In addition, I want to return all the values of the title attributes on the page within table rows.
using javascript only...
var rows = document.getElementById('all-items').getElementsByTagName('tr')
var titles = [];
for (var i = 0; i < rows.length; i++) {
titles.push(rows[i].getAttribute("title"));
}
console.log(titles);
<div id="all-items">
<table>
<tbody>
<tr title="Text 1"></tr>
<tr title="Text 2"></tr>
<tr title="Text 3"></tr>
</tbody>
</table>
</div>
The #WalksAway answer is fine. If you would like to reuse your jQuery selector though, you might look at querySelectorAll() as well.
var items = Array.from(document.querySelectorAll("#all-items table tbody tr"));
var titles = items.map(function(item) { return item.title; });
console.log(titles);
<div id="all-items">
<table>
<tbody>
<tr title="Text 1"></tr>
<tr title="Text 2"></tr>
<tr title="Text 3"></tr>
</tbody>
</table>
</div>
Having a problem with in ng-init and ng-repeat angularjs
i'm trying to loop the fields rates to get the total
for example this is my table
nane +++++++id+++++++rate
joe +++++++++1+++++++3
joe +++++++++2+++++++3
joe +++++++++3+++++++3
joe +++++++++4+++++++3
this my code.
<table>
<tr>
<td>name</td>
<td>rate</td>
</tr>
<tr ng-repeat="item in videos">
<td>{{item.name}}</td>
<td ng-init="videos.total.rate = videos.total.rate + item.rate">{{item.rate}}</td>
</tr>
<tr>
<td>Total</td>
<td>{{videos.total.rate}}</td>
</tr>
The Result that I get is 3333 instead of 12 when added all together
this is the line with problem
<td ng-init="videos.total.rate = videos.total.rate + item.rate">{{item.rate}}</td>
if i change it to a number it works fine.
<td ng-init="videos.total.rate = videos.total.rate + 3">{{item.rate}}</td>
your help would be great.thanks
Try something like this in controller.
JS
$scope.RateTotal= 0;
for (var i = 0; i < data.length; i++) {
$scope.RateTotal= $scope.RateTotal + data[i].rate;
}
HTML
<p>{{RateTotal}}</p>
Option above is better, but if you want use ng-init use something like this.
<table ng-init="RateTotal = 0">
<thead>
<th>Rate</th>
</thead>
<tbody>
<tr ng-repeat="item in videos">
<td ng-init="$parent.RateTotal= $parent.RateTotal + item.rate">{{item.rate}}</td>
</tr>
<tr>
<thead>
<tr>
<th>Total</th>
<th>{{RateTotal}}</th>
</tr>
</thead>
</tr>
</tbody>
</table>
P.S.
This directive can be abused to add unnecessary amounts of logic into
your templates. There are only a few appropriate uses of ngInit, such
as for aliasing special properties of ngRepeat, as seen in the demo
below; and for injecting data via server side scripting. Besides these
few cases, you should use controllers rather than ngInit to initialize
values on a scope. - ngInit
move this logic into the controller. That is what it is for. The view should be displaying data.
Now you have to worry about how to cast strings to an integer and writing 4x more code in a language that angular must interpret into javascript.
The complexity you are adding here is going to be fun to maintain.
but you probably want to continue doing it wrong, in which case this should work: <table ng-init='videos.total = {"rate": 0}'>
Define a filter to calculate the total:
app.filter('calculateRateTotal',function(){
return function(input){
var total = 0;
angular.forEach(input,function(value,key){
total = total+value.rate;
});
return total;
};
});
HTML:
<td ng-bind="videos | calculateRateTotal"></td>
After 10hrs of no luck just my managed to get it right. turned to be very simple.
This is the code.
In the Controller added
$scope.getTotal = function(){
var total = 0;
for(var i = 0; i < $scope.videos.length; i++){
var item = $scope.videos[i];
total += (item.rate*1);
}
return total; }
And HTML
<table>
<tr>
<th>Rate</th>
</tr>
<tr ng-repeat="item in videos">
<td>{{item.rate}}</td>
</tr>
<tr>
<td>Total: {{ getTotal() }}</td>
</tr>
</table>
Thanks everyone for helping
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>
I want to have an iterative moving over an array of users , and fill every td with a unique user in array, but I dont want to repeat and produce new html code in every ng-repeat's step.
I just want have a moving on the td's and for each one , put a user inside that td.
<!DOCTYPE html>
<html ng-app="fill">
<head>
<?php include "includes/head.php" ?>
<script type="text/javascript">
(function(){
var fill=angular.module("fill",[]);
fill.controller("fillTable",function($scope){
$scope.users=[ {name:"jack"},
{name:"joe"},
{name:"alen"},
{name:"mina"},
{name:"mari"},
{name:"karen"}
];
});
})()
</script>
</head>
<body>
<table ng-controller="fillTable" border=1>
<tbody ng-repeat="user in users">
<tr>
<td>user 1:{{user.name}}</td>
<td>user 2:{{user.name}}</td>
</tr>
<tr>
<td>user 3:{{user.name}}</td>
<td>user 4:{{user.name}}</td>
</tr>
<tr>
<td>user 5:{{user.name}}</td>
<td>user 6:{{user.name}}</td>
</tr>
</tbody>
</table>
</body>
</html>
actually, i have a grid with four columns that i created it by semantic-ui-grid.
now i want to read many articles from dataBase's tables then i have puting that datas inside grid's columns.{like a 'pinterest style' page } a pic for more explain , please see it
You can create pairs in controller:
$scope.users = [
{name:"jack"},
{name:"joe"},
{name:"alen"},
{name:"mina"},
{name:"mari"},
{name:"karen"}
];
$scope.pairs = [];
for (var i = 0; i < $scope.users.length; i+=2) {
$scope.users[i].index = i+1;
if ($scope.users[i+1]) {
$scope.users[i+1].index = i+2;
$scope.pairs.push([$scope.users[i], $scope.users[i+1]]);
} else {
$scope.pairs.push([$scope.users[i]]);
}
}
and iterate over pairs:
<table ng-controller="fillTable" border=1>
<tbody>
<tr ng-repeat="pair in pairs">
<td ng-repeat="user in pair">user {{user.index}}:{{user.name}}</td>
</tr>
</tbody>
</table>
There is no other workaround than to make a special array containing user pairs :
$scope.$watch('users', function() {
$scope.userPairs = [];
for (var i=0;i<$scope.users.length;i=i+2) {
$scope.userPairs.push({
name1 : $scope.users[i].name,
name2 : $scope.users[i+1].name
})
}
})
also use ng-repeat properly (you want to iterate over <tr>'s not <tbody>'s :
<table border=1>
<tbody>
<tr ng-repeat="user in userPairs">
<td>user 1:{{user.name1 }}</td>
<td>user 2:{{user.name2 }}</td>
</tr>
</tbody>
</table>
demo -> http://plnkr.co/edit/yK3F9US4XuS6sPnVv0Dd?p=preview
<table ng-controller="fillTable" border=1>
<tbody ng-repeat="user in users track by $index">
<tr>
<td>user 1:{{users[$index].name}}</td>
<td>user 2:{{users[$index+1].name}}</td>
</tr>
<tr>
<td>user 3:{{users[$index+2].name}}</td>
<td>user 4:{{users[$index+3].name}}</td>
</tr>
<tr>
<td>user 5:{{users[$index+4].name}}</td>
<td>user 6:{{users[$index+5].name}}</td>
</tr>
</tbody>
</table>
I have two javascript objects, the contents of which came from these two HTML tables.
Each pre-merge table now has it's own object. The object is structured as follows:
The first array element within the object contains the column headers from the pre-merge tables, and the array elements following that contain the <tr> data from each table.
Is it possible to merge these two objects together to produce one HTML table? As you can see the in the pre-merge tables the x-value is shared between both, meaning it is common between the two objects too. I thought there may be a way of comparing these values, and then populating the table, but I'm not sure how.
I would like the merged table to look like the following:
x-value: common dates shared between objects
columns: data from each of the pre-merge tables with their headers
Here is my code (you can also see it on this CodePenHere):
$(document).ready(function(){
gatherData();
results();
});
function gatherData(){
data = [];
tables = $('.before').find('table');
$(tables).each(function(index){
table = [];
var headers = $(this).find('tr:first');
var headerText = [];
headerText.push($(headers).find('td:nth-child(1)').text());
headerText.push($(headers).find('td:nth-child(2)').text());
table.push(headerText)
$(this).find('tr').each(function(index){
var rowContent = [];
if (index != 0){
$(this).find('td').each(function(index){
rowContent.push($(this).text());
})
}
table.push(rowContent)
})
data.push({table: table})
});
console.log(data)
}
function results(){
var results = $('.after1').find('thead');
$(results).append("<th>" + data[0].table[0][0] + "</th>");
for (i in data){
$(results).append("<th>" + data[i].table[0][1] + "</th>");
var b = data[i].table.length;
for (a = 2; a < b; a++){
console.log(data[i].table[a][0] + " || " + data[i].table[a][1])
}
}
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
<div class="container">
<h1 class="page-header">Formatter.js</h1>
</div>
<div class="container before">
<h3>Before</h3>
<table border=1 cellspacing=0 cellpadding=0 alignment="" class="a" id="3">
<tbody>
<tr>
<td>x-value</td>
<td>Operational Planned</td>
</tr>
<tr>
<td>09/11/2015</td>
<td>0</td>
</tr>
<tr>
<td>10/11/2015</td>
<td>0</td>
</tr>
<tr>
<td>11/11/2015</td>
<td>66358</td>
</tr>
<tr>
<td>12/11/2015</td>
<td>65990</td>
</tr>
<tr>
<td>13/11/2015</td>
<td>55993</td>
</tr>
<tr>
<td>14/11/2015</td>
<td>0</td>
</tr>
<tr>
<td>15/11/2015</td>
<td>0</td>
</tr>
</tbody>
</table>
<table border=1 cellspacing=0 cellpadding=0 alignment="" class="a" id="3">
<tbody>
<tr>
<td>x-value</td>
<td>Something Else</td>
</tr>
<tr>
<td>09/11/2015</td>
<td>0</td>
</tr>
<tr>
<td>10/11/2015</td>
<td>0</td>
</tr>
<tr>
<td>11/11/2015</td>
<td>2552</td>
</tr>
<tr>
<td>12/11/2015</td>
<td>86234</td>
</tr>
<tr>
<td>13/11/2015</td>
<td>33623</td>
</tr>
<tr>
<td>14/11/2015</td>
<td>0</td>
</tr>
<tr>
<td>15/11/2015</td>
<td>0</td>
</tr>
</tbody>
</table>
<hr>
</div>
<div class="container after">
<h3>After</h3>
<table class="table after1">
<thead>
</thead>
<tbody>
</tbody>
</table>
</div>
As I understand your issue, you want to merge the tables by the key values in coloumn x-value.
Here is how I would do it:
Collect data from each table into a dictionary with coloumn x-value as key
Save values for each key as array.
The main part is collecting the data in the dictionary. Here is the part:
var table = {
header: [],
data: {}
};
$(this).find('tr').each(function(index) {
// ignore first row
if (index === 0) return true;
// read all data for row
var rowData = [];
$(this).find('td').each(function() {
var value = $(this).text();
rowData.push(value);
});
// key value for dictionery
var key = rowData[0];
// add value to array in dictionary if existing or create array
if(table.data[key]) {
table.data[key].push(rowData[1]);
} else {
table.data[key] = [rowData[1]];
}
});
By using a simple javascript object as a dictionary we create properties on the fly, just like a dictionary.
See the plunker for the full script. I've written comments on the different parts to make the functionality clear. Let me know if anything is unclear.
As a note on your code. You can use multiple arguments in the jQuery selector to make your selections simpler, so this (see note below)
tables = $('.before').find('table');
can become this:
tables = $('.before table');
Edit
As noted by Mark Schultheiss in the comments, the later, but shorter syntax for jQuery selectors can be slower than the first one on large DOMs. So use the extended syntax on large DOMs. I've updated the plunker to use the better performing syntax.