I am getting some data from an external service and I am trying to show it on a table. The problem is that the data I get from service will be with dynamic columns, some times there will be 5 column another time 8. I don't know how I could handle it in ng-repeat. and using things like ng-grid won't be a good solution I think as there will be only 10 rows to display. for this If I use any external solution that will be a overhead. Is there any angular method to achieve this? if not what is the best option for this small data.
Note: Column names will also be dynamic
My code
<div ng-app='myApp' ng-controller="MainCtrl">
<div ng-repeat="prdElement in packageElement track by $index" class="package-grid">
<table class="hovertable">
<thead>
<tr>
<th>Line #</th>
<th>Quantity in Plt</th>
<th>Allready Packed</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="data in prdElement.Data" ng-init="data.newquantity = 0">
<td>{{data.itemId}}</td>
<td>
{{data.quantity}}
</td>
<td>{{data.packed}}</td>
</tr>
</tbody>
</table>
</div>
angular.module('myApp', []).controller('MainCtrl', function ($scope) {
var counter = 0;
$scope.packageElement = [{
name: counter,
show: true,
Data: [{
name: 'item 1',
itemId: '284307',
quantity: '100',
packed: 0
}, {
name: 'item 2',
itemId: '284308',
quantity: '200',
packed: 0
}]
}];
});
Will there be the same number of columns for all data items? If so, I think you can do this.
1. Define a function on your scope that gives you the object keys:
$scope.keys = function(obj) {
var key;
var keys = [];
for (key in obj) {
if (key === "$$hashKey") break; //angular adds new keys to the object
if (obj.hasOwnProperty(key)) keys.push(key);
}
return keys;
}
2. use a repeater on the table header (if the objects can have different properties, you need to find the object with the highest number of properties/columns)
<th ng-repeat="key in keys( prdElement.Data[0] )">{{key}}</th>
3. use a repeater on the table cell
<td ng-repeat="key in keys( prdElement.Data[0] )">{{ data[key] }}</td>
Related
Might be the end of the work day, might be the lack of coffee, but I just can't seem to come up with the correct idea for this.
I have an array with +- 180 rows of order data.
Now I would like to calculate the totals of the numbers to show them in the footer of my grid.
Can someone help me out?
Array looks something like this, yet much bigger:
[{title: 'title', description: 'description', someNumber: 'someNumber', otherNumber: 'otherNumber'},{title: 'title', description: 'description', someNumber: 'someNumber', otherNumber: 'otherNumber'}]
Here is my code:
var totalsRow = [];
this.someService.data().subscribe(newData => {
this.data = newData;
for (let row of newData) {
for (let col of this.cols) { //this.cols are all the fields in my array
if (this.isNumber(row[col.field])) { //This generates row[someNumber]
//Calculate total and push field to totalsRow
//So that I can loop through it in my HTML file.
} else {
//Push empty field to totalsRow
}
}
}
});
this.cols looks something like this:
[{field: 'title', header: 'Nice header title', visible: true, isNumber: false},
{field: 'someNumber', header: 'Nice header title', visible: true, isNumber: true}]
This is my HTML. I want to add a TFOOT with the totals of each field which is a number:
<thead>
<tr>
<ng-container *ngFor="let col of cols">
<th *ngIf="col.visible" class="text-uppercase small-label" style="white-space: nowrap;">
<div style="resize:both; overflow: auto; display:block">
{{col.header}}
</div>
</th>
</ng-container>
</tr>
</thead>
<tbody>
<tr *ngFor="let rowData of data" (click)="onRowSelect(rowData)">
<ng-container *ngFor="let col of cols">
<td *ngIf="col.visible" [ngClass]="{'text-center': col.isCentral}">
<span>{{rowData[col.field]}}</span>
</td>
</ng-container>
</tr>
</tbody>
What I want to achieve:
<tfoot>
<tr *ngFor="let rowData of totalsRow">
<td *ngIf="col.visible">
<span>{{rowData[col.field]}}</span>
</td>
</tr>
</tfoot>
Thanks in advance.
You have to bring out the totalsRow definition. If you declare it inside the subscribe the scope stays there and you can't access it.
...
var totalsRow = [];
this.someService.data().subscribe(newData => {
...
If the key is always someNumber
totalsRow = 0;
...
newData.forEach(datum => {
if(datum.someNumber){
this.totalsRow += datum.someNumber;
}
})
Ah well, found a solution myself.
I don't know if this would be the most neat answer, but it works for now:
I added a property total to my array of columns, and calculated the total per column.
for (let col of this.cols) {
if (col.isNumber) {
col.total = newData.reduce((a, b) => (a + b[col.field]), 0);
}
<tfoot>
<tr>
<ng-container *ngFor="let col of cols">
<td *ngIf="col.visible">
<span *ngIf="col.isNumber">{{col.total | currency: 'EUR'}}</span>
</td>
</ng-container>
</tr>
</tfoot>
I have an object that looks something like this:
{
item1: [element1, element2],
item2: [element1, element2],
item3: [element1, element2],
item4: [element1, element2]
}
What I'm trying to do is to print a table with each element of each array in a new row. This issue I'm having is how to get the contents without repeating an entire div or table with ng-repeat.
Example:
<table ng-repeat="(key, value) in accounts">
<tr ng-repeat="element in value">
<td>{{element}}</td>
</tr>
</table>
Which is giving me a new table for each key. I just one table with a row for each array element. Any way to do this with angular or do I need to use javascript?
It'd probably be easier to mash your elements into one array, then repeat over that array:
$scope.elements = Object.keys($scope.accounts).reduce(function(arr, key) {
return arr.concat($scope.accounts[key])
}, []);
And then the HTML:
<table>
<tr ng-repeat="element in elements">
<td>{{element}}</td>
</tr>
I am generating following json data from my database where keys like sid and name is static but task1,task2,task3 .... are dynamic and they can be upto value n(where n=1,2,3......)
My data:
[
{"sid":"10","name":"nam1","task1" :"1","task2" :"0","task3" :"1","task4" :"0","task5" :"0"},
{"sid":"20","name":"nam2","task1" :"0","task2" :"1","task3" :"0","task4" :"1","task5" :"1"},
{"sid":"30","name":"nam3","task1" :"1","task2" :"1","task3" :"0","task4" :"0","task5" :"1"},
{"sid":"40","name":"nam4","task1" :"0","task2" :"0","task3" :"0","task4" :"0","task5" :"1"}
]
app.js
app.controller('taskCrtl', function ($scope, $http, $timeout) {
$http.get('get.php').success(function(data){
$scope.list = data;
$scope.currentPage = 1; //current page
$scope.entryLimit = 5; //max no of items to display in a page
$scope.filteredItems = $scope.list.length; //Initially for no filter
$scope.totalItems = $scope.list.length;
});
Now i am trying to access key values using ng-repeat like below:
<tr ng-repeat="data in list| unique: 'sid'">
<td>{{data.sid }}</td>
<td>{{data.name}}</td>
<td>{{data.task1}}</td>
<td>{{data.task2}}</td>
<td>{{data.task3}}</td>
<td>{{data.task4}}</td>
<td>{{data.task5}}</td>
<tr/>
The above code works well for fixed keys like task1,task2,task3... but i am generating "task" key dynamically so it will be always unknown to me that how many task keys are there.There may be a case when there are keys from task1 to task100 so the above code will fail on that case.
I am trying to dynamically access the task keys to generate associate data.To achieve this i am concatenating a number( produced by an incremental loop) with the task key so that i becomes like task1,task2 .... value n
<tr ng-repeat="data in list| unique: 'sid'">
<td> {{ data.sid }} </td>
<td> {{ data.name }} </td>
<td ng-repeat="data in list| limitTo:n">
{{ id=$index+1; 'data.task'+id}}
</td>
</tr>
Id starts with 1 and incremented in every loop so that we can dynamically access data.task1,data.task2 and so on
I am facing two problems here.After concatenation i was supposed to get the value of a corresponding task key but i am getting like this data.task1,data.task2,data.task3 that is i am getting keys itself instead of key values.
The second problem is i want to loop up to n number of times so i am limiting the ng-repeat by n like this way ng-repeat="data in list| limitTo:n" but the value of n is unknown to me.Here n should be equal to the highest number of dynamic task key(or total task keys).
For example if in the data list there exist task1,task2,task3,task4,task5 then n will be 5 since there are total 5 task keys.If there exist task1 to task100 then n will be 100 as there are total 100 task keys.
One idea to achieve this could be counting total unique keys from the array and then subtract 2 static keys from it to get the number of dynamic keys which will be used as value of n to limit the loop.
For example in above data set the unique keys are sid,name,task1,task2,task3,task4,task5 if somehow we can manage to calculate total number of unique keys from the array then the total number of unique keys will be 7 in this case, and if we subtract 2 from the number 7 then we have 5 which is equal to the number of dynamic keys in the array, that we want to use as n to limit the loop.
Any idea how to solve my above problems using angularjs ?
I assume that the total number of task attributes on an Item may be varied.
By returning the list of Keys which start with Task you can iterate over that list instead and making it a function, you can call that during each iteration of ngRepeat:
$scope.getTaskKeys = function(row) {
return Object.keys(row).filter(function(keyname) {
return keyname.startsWith('task');
});
Leaving you free to call it as the collection for the second iteration:
<tr ng-repeat="data in list| unique: 'sid'">
<td> {{ data.sid }} </td>
<td> {{ data.name }} </td>
<td ng-repeat="taskKey in getTaskKeys(data)">
{{data[taskKey]}}
</td>
</tr>
Created a working example here: https://jsfiddle.net/zd1yjc0m/
Try this it will work as per your expectation..
var myApp = angular.module('myApp',[]);
myApp.controller('MyCtrl', function($scope) {
$scope.list = [
{"sid":"10","name":"nam1","task1" :"1","task2" :"0","task3" :"1","task4" :"0","task5" :"0"},
{"sid":"20","name":"nam2","task1" :"0","task2" :"1","task3" :"0","task4" :"1","task5" :"1"},
{"sid":"30","name":"nam3","task1" :"1","task2" :"1","task3" :"0","task4" :"0","task5" :"1"},
{"sid":"40","name":"nam4","task1" :"0","task2" :"0","task3" :"0","task4" :"0","task5" :"1"}
];
for (var i in $scope.list) {
var res = Object.keys($scope.list[i]).filter(item => { return item.indexOf("task") > -1; });
$scope.tasksList = res;
}
});
table,td {
border: 1px solid black;
padding: 5px;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="MyCtrl">
<table>
<tr ng-repeat="data in list">
<td> {{ data.sid }} </td>
<td> {{ data.name }} </td>
<td ng-repeat="item in tasksList"> {{ data[item] }} </td>
</tr>
</table>
</div>
data[0] contain the JSON data and data[1] contain dynamic key
<tr ng-repeat="x in data[0] ">
<td ng-repeat="j in data[1]">
[[ x[j] ]]
</td>
</tr>
Hi I am new to Angular and I am looking for some feedback. I am making a table with 4 columns:
check | stream | signal health | total signal.
I am using dummy data for the moment since I don't have an API. My issue is that I am not able to display multiple elements from the signal_health array as a value. Instead, Angular renders the array of objects into the UI as [{"id":1},{"id":2},{"id":3}] what I need is just the value.
I have to be able to display multiple values in just one td block, since every stream has multiple signal_health values. But I don't know how to accomplish this.
Any feedback will be welcomed thank you!
Here is the HTML below:
<table class="table table-striped table-bordered table-hover-alt">
<thead>
<tr>
<th>Select</th>
<th>Stream</th>
<th>Signal Health</th>
<th>Total Signals</th>
</tr>
</thead>
<tbody ng-cloak>
<tr ng-repeat="value in sc.reports">
<td><input type="checkbox" name="" value=""></td>
<td>{{value.stream}}</td>
<td>{{value.signal_health}}</td>
<td>{{value.total_signal}}</td>
</tr>
</tbody>
</table>
Here is my controller:
function SignalManagementController(){
var ctrl = this;
ctrl.reports =[
{stream:"MTV", signal_health:[{id:1}, {id:2}, {id:3}], status_cli:[ {value:5}, {value:3}, {value:4}, {value:5}], status_vde:[{value:5}, {value:3}, {value:4}, {value:5}], total_signal: 1},
{stream:"SciFy", signal_health:[{id:1}, {id:2}, {id:3}],status_cli:[{value:2, value:4, value:5}, {value:3}, {value:4}, {value:5}], status_vde:4, total_signal: 15},
{stream:"Spike", signal_health:[{id:1}, {id:2}, {id:3}],status_cli:4, status_vde:4, total_signal: 12},
{stream:"Nick", signal_health:[{id:1}, {id:2}, {id:3}], status_cli:4, status_vde:4, total_signal: 13},
{stream:"Cartoon", signal_health:[{id:1}, {id:2}, {id:3}], status_cli:4, status_vde:4,total_signal: 111},
{stream:"Starz", signal_health:[{id:1}, {id:2}, {id:3}], status_cli:4, status_vde:4, total_signal: 12}
];
}
You have at least three options to print the array values:
OPTION 1: Call a function of your controller from your html (PLUNKER)
CONTROLLER
function myCtrl(){
var ctrl = this;
ctrl.reports = [...]; //Your data
ctrl.showSignalHealth = function(signal_health){
return signal_health.map(function(item){
return item.id;
}).join(",");
}
}
HTML
<tr ng-repeat="value in ctrl.reports">
<td>{{value.stream}}</td>
<td>{{ctrl.showSignalHealth(value.signal_health)}}</td>
<td>{{value.total_signal}}</td>
</tr>
OPTION 2: Use a custom angular filter (PLUNKER)
CONTROLLER
app.filter('printSignalHealth', function() {
return function(signal_health) {
return signal_health.map(function(item){
return item.id;
}).join("-");
};
});
HTML
<tr ng-repeat="value in ctrl.reports">
<td>{{value.stream}}</td>
<td>{{value.signal_health | printSignalHealth}}</td>
<td>{{value.total_signal}}</td>
</tr>
OPTION 3: transform the data before repeating it in the HTML (PLUNKER)
CONTROLLER
function myCtrl(){
var ctrl = this;
ctrl.reports = getData();
function getData(){
var data = [..]; //Your data
for (let d of data) {
d.signal_health = d.signal_health.map(function(item){
return item.id;
}).join(" | ");
}
return data;
}
}
HTML (Just repeat the data and will works)
<tr ng-repeat="value in ctrl.reports">
<td>{{value.stream}}</td>
<td>{{value.signal_health}}</td>
<td>{{value.total_signal}}</td>
</tr>
You can use a map function on the array to return the nested value you want.
In your html, replace your line for the signal health:
<td rowspan="{{sc.reports.signal_health.length}}">{{value.signal_health}}</td>
with this line:
<td rowspan="{{sc.reports.signal_health.length}}">{{value.signal_health.map(function(obj) { return obj.id; })}}</td>
<table>
<thead>
<tr>
<th class="col-md-3" ng-click="sortDirection = !sortDirection">Created At</th>
</tr>
</thead>
<tbody>
<tr dir-paginate="food in foods | filter:foodFilter | itemsPerPage:pageSize | orderBy:'created_at_date'">
<td class="col-md-"> {{food.created_at_date}} </td>
</tbody>
</table>
<dir-pagination-controls
max-size= 7
boundary-links="true">
</dir-pagination-controls>
This is only a snippet of my code but its too large to put up. Everything is working except only some of the created_at_date is in order. When I click on a different filter to add in or remove data depending on that filter, only some of it is entered into the correct place. My main question is: is there someway to sort all of the dates properly while still allowing the everything else function as well? All help is welcome, Thanks
(function () {
"use strict";
App.controller('foodsController', ['$scope'],
function($scope) {
$scope.sortDirection = true;
In your controller you can add the method to order the array before you loop over them.
Assuming your foods array has an array of objects, each with a key of created_at_date and a value:
App.controller('foodsController', function($scope) {
$scope.foods = [{
created_at_date: 6791234
}, {
created_at_date: 9837245
}, {
created_at_date: 1234755
}];
// create a method exposed to the scope for your template.
$scope.orderBy = function(key, array) {
// now you've received the array, you can sort it on the key in question.
var sorted = array.sort(function(a, b) {
return a[key] - b[key];
});
return sorted;
}
});
Now on your template, you have a method available to sort your values for you:
<table>
<thead>
<tr>
<th class="col-md-3" ng-click="sortDirection = !sortDirection">Created At</th>
</tr>
</thead>
<tbody>
<tr dir-paginate="food in orderBy('created_at_date', foods) | filter:foodFilter | itemsPerPage:pageSize">
<td class="col-md-"> {{food.created_at_date}} </td>
</tr>
</tbody>
</table>
The orderBy method which we've created on your controller returns an array, but it's just sorted by the key that's sent in as the first argument of the function. The second argument is the original array you're trying to sort.
At least this way you can check if you remove all your other filters to see if it's ordered correctly, if then after you add them back in it changes it's because those filters are also changing the order.