AngularJS Table creation with ng-repeat - javascript

I get following response from database. about array of classes where classes are nested in groups and finally students.
"Response":[
{
"Id":1,"Name":"Class 1","Location":"Building 1","Groups":[
{
"Id":1,"Name":"GB1","Students":[
{
"Id":1,"Name":"Mike","RollNo":"1","Performance":{
"Id":1,"Math":"90","Physics":"70","English":"60"
}
},{
"Id":2,"Name":"John","RollNo":"2","Performance":{
"Id":2,"Math":"90","Physics":"70","English":"60"
}
},{
"Id":3,"Name":"Muffin","RollNo":"3","Performance":{
"Id":3,"Math":"90","Physics":"90","English":"90"
}
}
]
}, {
"Id":2,"Name":"GB2","Students":[
{
"Id":4,"Name":"Ema","RollNo":"1","Performance":{
"Id":4,"Math":"90","Physics":"70","English":"60"
}
},{
"Id":5,"Name":"Sunny","RollNo":"2","Performance":{
"Id":5,"Math":"90","Physics":"70","English":"60"
}
},{
"Id":6,"Name":"Jen","RollNo":"3","Performance":{
"Id":6,"Math":"90","Physics":"90","English":"90"
}
}
]
}
]
},{
"Id":2,"Name":"Class 2","Location":"Building 1","Groups":[
{
"Id":3,"Name":"G1","Students":[
{
"Id":7,"Name":"Ron","RollNo":"1","Performance":{
"Id":7,"Math":"90","Physics":"70","English":"60"
}
},{
"Id":8,"Name":"Kaka","RollNo":"2","Performance":{
"Id":8,"Math":"90","Physics":"70","English":"60"
}
},{
"Id":9,"Name":"Mark","RollNo":"3","Performance":{
"Id":9,"Math":"90","Physics":"90","English":"90"
}
}
]
}, {
"Id":4,"Name":"G2","Students":[
{
"Id":10,"Name":"Lily","RollNo":"1","Performance":{
"Id":10,"Math":"90","Physics":"70","English":"60"
}
},{
"Id":11,"Name":"Lina","RollNo":"2","Performance":{
"Id":11,"Math":"90","Physics":"70","English":"60"
}
},{
"Id":12,"Name":"Linda","RollNo":"3","Performance":{
"Id":12,"Math":"90","Physics":"90","English":"90"
}
}
]
}
]
}
]
Now I want to create a table like this using colspan.
Could anyone help me to do this using ng-repeat and angularjs ? can't figure out how to merge this columns dynamically. So far I managed to do last part using flatten array option.

To solve this problem, you will need to ng-repeat inside the <td> instead of <tr>, for most of the time. Other than that, it is just rather tedious work parsing around your object and align them in the manner you want.
Here is the plnkr: http://plnkr.co/edit/aNVrMa4E8gLkVYlxzdHF?p=preview
I am poor at css. Maybe you can do something about that.

Although in this solution I had to add add few JavaScript method I still expect to see a better solution and accept as an answer. DEMO
<!DOCTYPE html>
<html ng-app = "demo">
<head>
<script data-require="angular.js#*" data-semver="1.3.0-beta.5" src="https://code.angularjs.org/1.3.0-beta.5/angular.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body ng-controller = "demoCtrl">
<h1>Hello Plunker!</h1>
<br>
<table>
<tr>
<td>Class name</td>
<td colspan="{{lengthCount(r)}}" ng-repeat ="r in response" >
{{r.Name}}
</td>
</tr>
<tr>
<td>Group name</td>
<td colspan="{{gr.Students.length}}" ng-repeat ="gr in Groups" >
{{gr.Name}}
</td>
</tr>
<tr>
<td>Student name</td>
<td ng-repeat ="st in Studs" >
{{st.Name}}
</td>
</tr>
<tr>
<td>Maths</td>
<td ng-repeat ="st in Studs" >
{{st.Performance.Math}}
</td>
</tr>
<tr>
<td>Physics</td>
<td ng-repeat ="st in Studs" >
{{st.Performance.Physics}}
</td>
</tr>
<tr>
<td>English</td>
<td ng-repeat ="st in Studs" >
{{st.Performance.English}}
</td>
</tr>
</table>
<br>
</body>
</html>
Code goes here
angular.module("demo",[])
.controller("demoCtrl", ['$scope', function($scope){
$scope.response = response;
function flattenArray(array, fn) {
var output = [];
console.log("<i was flatten here");
for (var i = 0; i < array.length; ++i) {
var result = fn(array[i]);
if (result)
output = output.concat(result);
}
return output;
}
$scope.lengthCount = function(obj) {
var k = 0;
console.log("<i was flatten here");
for (var i = 0; i < obj.Groups.length; ++i) {
k= k+ obj.Groups[i].Students.length;
}
return k;
}
$scope.Groups = flattenArray($scope.response, function (item) {
console.log("<i was here");
return item.Groups;
});
$scope.Studs = flattenArray($scope.Groups, function (item) {
console.log("<i was here");
return item.Students;
});
}]);
var response = [{
"Id":1,"Name":"Class 1","Location":"Building 1","Groups":[
{
"Id":1,"Name":"GB1","Students":[
{
"Id":1,"Name":"Mike","RollNo":"1","Performance":{
"Id":1,"Math":"90","Physics":"70","English":"60"
}
},{
"Id":2,"Name":"John","RollNo":"2","Performance":{
"Id":2,"Math":"90","Physics":"70","English":"60"
}
},{
"Id":3,"Name":"Muffin","RollNo":"3","Performance":{
"Id":3,"Math":"90","Physics":"90","English":"90"
}
}
]
}, {
"Id":2,"Name":"GB2","Students":[
{
"Id":4,"Name":"Ema","RollNo":"1","Performance":{
"Id":4,"Math":"90","Physics":"70","English":"60"
}
},{
"Id":5,"Name":"Sunny","RollNo":"2","Performance":{
"Id":5,"Math":"90","Physics":"70","English":"60"
}
},{
"Id":6,"Name":"Jen","RollNo":"3","Performance":{
"Id":6,"Math":"90","Physics":"90","English":"90"
}
}
]
}
]
},{
"Id":2,"Name":"Class 2","Location":"Building 1","Groups":[
{
"Id":3,"Name":"G1","Students":[
{
"Id":7,"Name":"Ron","RollNo":"1","Performance":{
"Id":7,"Math":"90","Physics":"70","English":"60"
}
},{
"Id":8,"Name":"Kaka","RollNo":"2","Performance":{
"Id":8,"Math":"90","Physics":"70","English":"60"
}
},{
"Id":9,"Name":"Mark","RollNo":"3","Performance":{
"Id":9,"Math":"90","Physics":"90","English":"90"
}
}
]
}, {
"Id":4,"Name":"G2","Students":[
{
"Id":10,"Name":"Lily","RollNo":"1","Performance":{
"Id":10,"Math":"90","Physics":"70","English":"60"
}
},{
"Id":11,"Name":"Lina","RollNo":"2","Performance":{
"Id":11,"Math":"90","Physics":"70","English":"60"
}
},{
"Id":12,"Name":"Linda","RollNo":"3","Performance":{
"Id":12,"Math":"90","Physics":"90","English":"90"
}
}
]
}
]
}
]

Related

How to create a table with indents from nested JSON in angularjs

I get a nested JSON object back from an API call that looks something along the lines of this:
{
"name": “Main “Folder”,
"children": [
{
"name": “Child Folder 1”,
"children": []
},
{
"name": “Child Folder 2”,
"children": [
{
"name": “Sub Folder 1”,
"children": [
{
“name”: “Sub Sub Folder 1”,
“children”: []
}
]
},
{
"name": “Sub Folder 2” ,
"children": []
}
]
}
]
}
There is no limit on how far the JSON object can be nested so that is unknown to me. I need to have all of the children of the folders to be indented under the parent in the table. I'm not really even sure how to go about doing this. The first thing I tried was doing something like this in my HTML file, but I quickly realized it wasn't going to work.
folders.html
<table>
<thead>
<tr><strong>{{ this.tableData.name }}</strong></tr>
</thead>
<tbody ng-repeat="b in this.tableData.children">
<tr>
<td>{{ b.name }}</td>
<td ng-repeat="c in b.children">{{ c.name }}</td>
</tr>
</tbody>
</table>
folders.js
export default class FoldersController {
constructor($rootScope, $scope, $uibModal) {
this.tableData = {Example Data from top}
}
}
Is there a not too complicated way to go about doing this? Thanks!
You should create a component with a template that contains a table, then you can nest your component inside itself to follow the tree structure logical path:
Your root controller should contain your table data:
angular.module('app').controller('RootCtrl', ['$scope', function($scope) {
// assigning the data to $scope to make it available in the view
$scope.tableData = {Example Data from top};
}]);
Your tree component could be something on this lines:
angular.module('app').component('treeComponent', {
controller: 'TreeCtrl',
bindings: {
tree: '<',
},
templateUrl: 'tree-view.html'
});
your root template should load the first instance of the component:
<div>
<tree-component tree="tableData"></tree-component>
</div>
then the component template should take care of the the recursion when required;
tree-view.html:
<table class="record-table">
<thead>
<tr>
<th>
<strong>{{ $ctrl.tableData.name }}</strong>
</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="node in $ctrl.tableData.children">
<td>{{node.name}}</td>
<td ng-if="node.children.length > 0">
<tree-component tree="node.children"></tree-component>
</td>
</tr>
</tbody>
</table>
creating indentation then becomes easy using basic css:
.record-table .record-table {
padding-left: 20px
}
I was able to figure out a solution of my own using recursion in the js file. I implemented mindthefrequency's answer as well and it seems to be working just fine. I'm marking it as the best answer because it seems to be the cleaner solution, but I'm posting what I have in case someone wants to take a more js oriented approach.
First, in the js file, use recursion to add all of the nodes and how far each needs to be indented to the table data variable.
folders.js
export default class FoldersController {
constructor($rootScope, $scope, $uibModal) {
this.resp = {Example Data from top}
this.tableData = []
this.createTable(this.resp.children, 0, [
{
name: this.resp.name,
indent: '0px',
},
]);
}
createTable(children, count, data) {
count += 1;
// base case
if (!children || children.length === 0) {
return;
}
for (const child of children) {
const { name } = child;
const returnData = data;
returnData.push({
name: name,
indent: `${count * 25}px`,
});
this.tableData = returnData;
this.createTable(child.children, count, returnData);
}
}
}
Then, in the html file, use angularjs to properly indent each node
folders.html
<table>
<thead>
<tr><strong>Table Header</strong></tr>
</thead>
<tbody ng-repeat="b in vm.tableData">
<tr>
<td ng-style="{'padding-left': b.indent}">{{ b.name }}</td>
</tr>
</tbody>
</table>

Reset the data on table using reset button

learning javascript by doing (beginner), here i have a table where is 'animals' and 'persons' want to know is there a way to reset table data back to 'Animal' after selecting data from select box ? i thought by calling the whole thing again inside onclick would do the trick but...
my code :
function myFunction() {
paivitys()
}
function paivitys(data, arvvoja) {
console.log(data);
//----
if (data.hasOwnProperty("animal")) {
document.getElementById("1name").innerHTML = data.animal;
} else {
document.getElementById("1name").innerHTML = data.person;
document.getElementById("1name1").innerHTML = 'person';
}
//----
if (data.hasOwnProperty("animal2")) {
document.getElementById("2name").innerHTML = data.animal2;
} else {
document.getElementById("2name").innerHTML = data.person2;
document.getElementById("2name1").innerHTML = 'person';
}
//-----
document.getElementById("id").innerHTML = data.id;
}
function paivitaselekt(data, arvvoja) {
for (var i = 0; i < data.length; i++) {
var select = document.getElementById("Select");
var option = document.createElement("option");
arvvoja.forEach((value) => {
option.textContent += data[i][value] + " ";
});
select.appendChild(option);
}
}
data = {
"animal": "tiger",
"animal2": "lion",
"id": "54321",
"dole": {
"Key": "fhd699f"
}
}
paivitys(data);
let kokoarray;
data = [{
"person": "kaka",
"person2": "julle",
"id": "9874",
},
{
"person": "Ronaldo",
"person2": "jussi",
"id": "65555",
}
]
kokoarray = data;
paivitaselekt(data, ["person", "id"]);
document.getElementById("Select").addEventListener("change", function(event) {
const valittutunnsite = event.target.value.split(" ")[1];
const valittutieto = kokoarray.filter((data) => data.id === valittutunnsite)[0];
paivitys(valittutieto);
});
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" />
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.6.3/css/all.css" integrity="sha384-UHRtZLI+pbxtHCWp1t77Bi1L4ZtiqrqD80Kn4Z8NTSRyMA2Fd33n5dQ8lWUE00s/" crossorigin="anonymous" />
<div class="container">
<table class="table ">
<thead>
<tr>
<th style="width: 25%;" id="1name1" class="table-primary">Animal</th>
<th style="width: 25%;" id="2name1" class="table-primary">Animal</th>
<th style="width: 25%;" class="table-primary">id</th>
</tr>
</thead>
<tbody>
<th id="1name"></th>
<th id="2name"></th>
<th id="id"></th>
</tbody>
</table>
<select id="Select" name="name"></select>
<button onclick="myFunction()">Reset</button>
</div>
Works this.
let animals
let animalCols = ['Animal', 'Animal 2']
let peopleCols = ['Person', 'Person 2']
function myFunction() {
paivitys(animals, animalCols)
}
function paivitys(data, arvvoja) {
console.log(data);
//----
if (data.hasOwnProperty("animal")) {
document.getElementById("1name").innerHTML = data.animal;
} else {
document.getElementById("1name").innerHTML = data.person;
}
//----
if (data.hasOwnProperty("animal2")) {
document.getElementById("2name").innerHTML = data.animal2;
} else {
document.getElementById("2name").innerHTML = data.person2;
}
document.getElementById("1name1").innerHTML = arvvoja[0];
document.getElementById("2name1").innerHTML = arvvoja[1];
//-----
document.getElementById("id").innerHTML = data.id;
}
function paivitaselekt(data, arvvoja) {
for (var i = 0; i < data.length; i++) {
var select = document.getElementById("Select");
var option = document.createElement("option");
arvvoja.forEach((value) => {
option.textContent += data[i][value] + " ";
});
select.appendChild(option);
}
}
animals = {
"animal": "tiger",
"animal2": "lion",
"id": "54321",
"dole": {
"Key": "fhd699f"
}
}
paivitys(animals, animalCols);
let kokoarray;
people = [{
"person": "kaka",
"person2": "julle",
"id": "9874",
},
{
"person": "Ronaldo",
"person2": "jussi",
"id": "65555",
}
]
kokoarray = people;
paivitaselekt(kokoarray, ["person", "id"]);
document.getElementById("Select").addEventListener("change", function(event) {
const valittutunnsite = event.target.value.split(" ")[1];
const valittutieto = kokoarray.filter((data) => data.id === valittutunnsite)[0];
paivitys(valittutieto, peopleCols);
});
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" />
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.6.3/css/all.css" integrity="sha384-UHRtZLI+pbxtHCWp1t77Bi1L4ZtiqrqD80Kn4Z8NTSRyMA2Fd33n5dQ8lWUE00s/" crossorigin="anonymous" />
<div class="container">
<table class="table ">
<thead>
<tr>
<th style="width: 25%;" id="1name1" class="table-primary">Animal</th>
<th style="width: 25%;" id="2name1" class="table-primary">Animal</th>
<th style="width: 25%;" class="table-primary">id</th>
</tr>
</thead>
<tbody>
<th id="1name"></th>
<th id="2name"></th>
<th id="id"></th>
</tbody>
</table>
<select id="Select" name="name"></select>
<button onclick="myFunction()">Reset</button>
</div>
I updated the code:
set columns
let animalCols = ['Animal', 'Animal 2']
let peopleCols = ['Person', 'Person 2']
udpate data
paivitys(animals, animalCols)
and
function paivitys(data, arvvoja) {
...
document.getElementById("1name1").innerHTML = arvvoja[0];
document.getElementById("2name1").innerHTML = arvvoja[1];
//...
}
Your reset button calls the function:
function myFunction() {
paivitys()
}
Which calls the paivitys function with no arguments.
function paivitys(data, arvvoja) {
The function takes data as its first argument, but you are not passing any variable to it.
This line is failing:
if (data.hasOwnProperty("animal")) {
Because data is undefined.
But as well as this, you are defining your data using animals, and then later changing the data to contain people. So the animals data is lost. You need to use a different variable to store people data.

VUE watch triggered infinite loop

I'm new to using VUE.Js, and i created a very simple app to try out how it works.
The problem happens immediately where when i run the app, the watch for a variable is triggered in an infinite loop. I cannot figure out why. There is a v-for loop but that is on an array that only has two elements.
Initially the SubTotal should be 0. But as soon as the app is run, it triggers the Buy method, even though i haven't clicked the buy button and the sub total ends up being 442.37999999999965.
Thanks for any help.
Here is the jsfiddle Beer shopping cart
HTML :
<div id = "growler">
<table>
<tr>
<th style='width:150px'>Beer</th>
<th style='width:50px'>Price</th>
<th style='width:30px'></th>
</tr>
<tr v-for = "beer in beers">
<td>{{ beer.name }}</td>
<td>{{ beer.price }}</td>
<td>
<button :click="buy(beer)">buy</button>
</td>
</tr>
<tr>
<td>SubTotal</td>
<td>{{subTotal}}</td>
<td></td>
</tr>
</table>
</div>
JS:
new Vue({
el: "#growler",
data: {
beers: [
{name: 'Ahool Ale', price: 2.00},
{name: 'Agogwe Ale', price: 2.38}
],
shoppingCart: [],
subTotal: 0.00
},
watch: {
shoppingCart: function() {
console.log('shopping cart watch triggered');
this.updateSubTotal();
}
},
methods: {
updateSubTotal: function () {
var s=this.shoppingCart.length;
var t=0;
for (var i=0;i<s; i++){
t += this.shoppingCart[i].price;
}
this.subTotal = t;
},
buy: function (beer) {
console.log('beer pushed on array');
this.shoppingCart.push(beer);
}
},
beforeCreate: function() {
console.log('beforeCreate');
},
created: function() {
console.log('created');
},
beforeMount: function() {
console.log('beforeMount');
},
mounted: function() {
console.log('mounted');
},
beforeUpdate: function() {
console.log('beforeUpdate');
},
updated: function() {
console.log('updated');
},
beforeDestroy: function() {
console.log('beforeDestroy');
},
destroyed: function() {
console.log('afterDestroy');
}
});
I found your mistake:
<button :click="buy(beer)">buy</button>
You used :(v-bind) instead of #(v-on:) on the click handler.
When you first bind it, the function is called once and updates the shoppingCart. This will update the subTotal data, which will force a re-render of the DOM, which will trigger the buy function again because of the :bind.
Fix:
<button #click="buy(beer)">buy</button>
<!-- or -->
<button v-on:click="buy(beer)">buy</button>
Suggested changes for your code:
Use computed properties instead of a method to update a property that represents a sum of other values:
new Vue({
el: "#growler",
data: {
beers: [{
name: 'Ahool Ale',
price: 2.00
},
{
name: 'Agogwe Ale',
price: 2.38
}
],
shoppingCart: []
},
watch: {
shoppingCart: function() {
console.log('shopping cart watch triggered');
}
},
computed: {
subTotal: function() {
return this.shoppingCart.reduce(function(total, beer) {
return total + beer.price;
}, 0);
}
}
},
methods: {
buy: function(beer) {
this.shoppingCart.push(beer);
}
},
});
<script src="https://cdn.jsdelivr.net/npm/vue#2.5.13/dist/vue.js"></script>
<div id="growler">
<button>buy</button>
<table>
<tr>
<th style='width:150px'>Beer</th>
<th style='width:50px'>Price</th>
<th style='width:30px'></th>
</tr>
<tr v-for="beer in beers">
<td>{{ beer.name }}</td>
<td>{{ beer.price }}</td>
<td>
<button #click="buy(beer)">buy</button>
</td>
</tr>
<tr>
<td>SubTotal</td>
<td>{{subTotal}}</td>
<td></td>
</tr>
</table>
</div>

How to avoid multiple map functionality

I have two objects. First one have entire school full details of students record. Example like
var first = {
students:
[
{ id:'1', name:"suresh", age:"20", degree:"BSc", status:"obsent"},
{ id:'2', name:"ramesh", age:"21", degree:"BCom", status:"present"},
{ id:'3', name:"rajesh", age:"19", degree:"BA", status:"leave"},
{ id:'4', name:"satish", age:"28", degree:"BL", status:"obsent"}
]
}
Second one have particular class students information about the status of the student for that day. Example like
var second ={
students:
[
{ id:'1',status:"present"},
{ id:'12',status:"obsent"},
{ id:'3',status:"obsent"},
{ id:'14',status:"leave"}
]
}
Now I need to compare the student id and need to display the status based on the result. I have achieved in the following way.
items = first.students.map(function(item){
status =item.status;
second.students.map(function(key){
if(key.id == item.id) { status = key.status }
});
return "<tr><td>"+item.name+"</td><td>"+item.age+"</td><td>"+item.degree+"</td><td>"+status+"</td></tr>";
});
$('table#main tbody').html(items);
The above code is working fine. But if you look at my code, I have used the map functionality multiple times. I feel that I have done something wrong in the performance wise. Is that possible to reduce using the map twice or any other better way to achieve the same result. Please suggest me.
Code Snippet
var first = {
students:
[
{ id:'1', name:"suresh", age:"20", degree:"BSc", status:"obsent"},
{ id:'2', name:"ramesh", age:"21", degree:"BCom", status:"present"},
{ id:'3', name:"rajesh", age:"19", degree:"BA", status:"leave"},
{ id:'4', name:"satish", age:"28", degree:"BL", status:"obsent"}
]
}
var second ={
students:
[
{ id:'1',status:"present"},
{ id:'12',status:"obsent"},
{ id:'3',status:"obsent"},
{ id:'14',status:"leave"}
]
}
items = first.students.map(function(item){
status =item.status;
second.students.map(function(key){
if(key.id == item.id) { status = key.status }
});
return "<tr><td>"+item.name+"</td><td>"+item.age+"</td><td>"+item.degree+"</td><td>"+status+"</td></tr>";
});
$('table#main tbody').html(items);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table id="main" cellspacing="2" border="1">
<thead>
<tr>
<th>Name</th>
<th>Age</th>
<th>Degree</th>
<th>Stauts</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</tbody>
</table>
Due to the way your objects are set up, it looks like that will be O(n) time for the lookup, because you need to loop through the first student array for every student id.
To get around this, you can do a single map where you assign the id as the key of a new intermediate object in the format of:
x = {1: {...}, 2: {...}}
From there, you can now do constant time O(1) lookups:
x[id]
The only extra work is building the intermediate hash, but that will be less computation than what you have above.
See this example below. Note that it does use 2 maps, but it's different than your example because it's not a map within a map which is exponential:
var students = [
{ id:'1', name:"suresh", age:"20", degree:"BSc", status:"obsent"},
{ id:'2', name:"ramesh", age:"21", degree:"BCom", status:"present"},
{ id:'3', name:"rajesh", age:"19", degree:"BA", status:"leave"},
{ id:'4', name:"satish", age:"28", degree:"BL", status:"obsent"}
];
var studentIds = {};
students.forEach(function(student) {
studentIds[student.id] = {name: student.name, age: student.age, degree: student.degree, status: student.status}
});
var second = [
{ id:'1',status:"present"},
{ id:'12',status:"obsent"},
{ id:'3',status:"obsent"},
{ id:'14',status:"leave"}
];
var studentStatuses = second.map(function(student) {
// do whatever you have to do here
return (studentIds[student.id] || {}).status;
});
The complexity will be better if you build an object which keys are id and values are status from second.students then you update status in first.students based on this object:
var first = {
students:
[
{ id:'1', name:"suresh", age:"20", degree:"BSc", status:"obsent"},
{ id:'2', name:"ramesh", age:"21", degree:"BCom", status:"present"},
{ id:'3', name:"rajesh", age:"19", degree:"BA", status:"leave"},
{ id:'4', name:"satish", age:"28", degree:"BL", status:"obsent"}
]
}
var second ={
students:
[
{ id:'1',status:"present"},
{ id:'12',status:"obsent"},
{ id:'3',status:"obsent"},
{ id:'14',status:"leave"}
]
}
var statusById= second.students.reduce(function(m, e) {
m[e.id] = e.status;
return m;
}, {});
items = first.students.map(function(item){
item.status = statusById[item.id] || item.status;
return "<tr><td>"+item.name+"</td><td>"+item.age+"</td><td>"+item.degree+"</td><td>"+item.status+"</td></tr>";
});
$('table#main tbody').html(items);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table id="main" cellspacing="2" border="1">
<thead>
<tr>
<th>Name</th>
<th>Age</th>
<th>Degree</th>
<th>Stauts</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</tbody>
</table>

Flexible table ng-repeat

Is the following possible and if so how do I change my HTML to allow it?
I have the following model;
prospect = [{"name":"jamie",
"phones": [{
"type":"home",
"number":"01275"},
{
"type":"mobile",
"number":"0788"}]},
{"name":"peter",
"phones": [{
"type":"mobile",
"number":"07852"}]}
]
and I would like to display - in an angularjs table - like this
name home mobile
jamie 01275 0788
peter 07852
My current HTML
<table>
<tbody ng-repeat='person in prospect'>
<th>Name</th>
<th ng-repeat="phone in person.phones">{{phone.type}}</th>
<tr>
<td>
{{person.name}}
</td>
<td ng-repeat='phone in person.phones'>
{{phone.number}}
</td>
</tr>
</tbody>
</table>
produces
Name home mobile
jamie 01275 0788
Name mobile
peter 07852
http://jsfiddle.net/jaydubyasee/D7f2k/
To do this in html, without modifying your json, I'd first add an array that indicates what type of phone goes into each column:
$scope.types= ["home","mobile"];
Then use it in the header:
<th ng-repeat="type in types">{{type}}</th>
Then to print out the phone numbers we iterate over each phone within each column, using ngIf to conditionally show any phones that match that column's type:
<td ng-repeat='type in types'>
<span ng-repeat='pphone in person.phones' ng-if="pphone.type == type">
{{pphone.number}}
</span>
</td>
updated fiddle
A variation would be to replace the nested ngRepeats with a custom directive that displays the correct phone for the given column and row.
I hope you will like this solution :)
I did you this dependency
bower install angular
bower install ng-tasty
bower install bootstrap
And here the full solution
<div tasty-table bind-resource="resource">
<table class="table table-striped table-condensed">
<thead tasty-thead></thead>
<tbody>
<tr ng-repeat="row in rows">
<td ng-bind="row.name"></td>
<td ng-bind="row.phones | filterTypeColumn:'home'"></td>
<td ng-bind="row.phones | filterTypeColumn:'mobile'"></td>
</tr>
</tbody>
</table>
</div>
<script src="bower_components/angular/angular.min.js"></script>
<script src="bower_components/ng-tasty/ng-tasty-tpls.min.js"></script>
<script>
angular.module('stackOverflowAnswer', ['ngTasty'])
.filter('filterTypeColumn', function() {
return function (input, typeColumn) {
var phoneNumber;
input.forEach(function (phone) {
if (phone.type === typeColumn) {
phoneNumber = phone.number;
}
})
return phoneNumber;
};
})
.controller('StackOverflowController', function ($scope) {
$scope.resource = {
"header": [
{ "name": "Name" },
{ "home": "Home" },
{ "mobile": "Mobile" }
],
"rows": [
{
"name":"jamie",
"phones": [
{ "type":"home","number":"01275" },
{ "type":"mobile", "number":"0788"}
]
},
{
"name":"peter",
"phones": [
{ "type":"mobile","number":"07852"}
]
}
]
};
});
</script>
</body>
</html>
If you want know more about ngTasty you can find all the doc here http://zizzamia.com/ng-tasty/directive/table .
For your specific case, the solution was make a custom filter.
Ciao

Categories

Resources