I receive a Json that looks like this (I dont have access to change it)
{
"name": "mike"
"days": [
{
"timeperiods": [
{
"time": "08:00 - 12:00",
"hours": 4,
"task": "running"
},
{
"time": "13:00 - 15:00",
"hours": 4,
"task": "triathlon"
}
]
},
{
"timeperiods": [
{
"time": "08:00 - 12:00",
"hours": 3,
"task": "swimming"
}
]
}
]
}
Its not an full JSON-Example. Usually there would be 6 days objects. But i think showing 2 Objects should show my problem.
I create an table in html which shows me what tasks an user has on certain days.
(I save the JSON Data in a scope variable with the name weekplan.)
<table>
<thead>
<tr>
<th>Time</th>
<th>Monday</th>
<th>Tuesday</th>
<th>Wedesday</th>
<th>Thursday</th>
<th>Friday</th>
<th>Saturday</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="day in weekplan.days[0].timeperiods">
<td>{{day.time}}</td>
<td ng-if="day.hours == 0"><div></div></td>
<td ng-if="day.hours != 999 && day.hours != 0">Time for Workout!!</td>
</tr>
</tbody>
</table>
It can only be one ng-if true never both.
My Problem is to display the Columns correctly. This table example works but only for the time column and the monday column. But i dont know how to get it to work on all weekdays. I thought about using ng-if and ng-repeat on the same td object but it didnt really work out. (I need both ng-if for CSS rules which i have removed from this example cause its not part of the problem). What i want in the End is a table which either shows an empty field for a certain timeperiod or a field where it says "Time for Workout". And this for all Weekdays.
You have very confusing description, but if logically present your json it will look something like:
HTML
<table>
<thead>
<tr>
<th>Time</th>
<th>Monday</th>
<th>Tuesday</th>
<th>Wedesday</th>
<th>Thursday</th>
<th>Friday</th>
<th>Saturday</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="day in weekplan.days">
<td data-ng-repeat="period in day.timeperiods">
<span>{{day.time}}</span>
<span ng-if="day.hours == 0"></span> <!-- why it is even exist? -->
<span ng-if="day.hours != 999 && day.hours != 0">Time for Workout!! </span>
</td>
</tr>
</tbody>
</table>
So far I've only found examples that put the objects in the rows (1)(2)(3), but I need to put the objects in the columns and their attributes in the rows.
Example of JSON:
[
{
name: 'peanut butter',
price: 0.99
}
{
name: 'strawberry jelly',
price: 0.99
}
{
name: 'white bread',
price: 2.99
}
]
Example of desired table:
I think you want something like this.
Angular template:
<table>
<tr>
<th>Name</th>
<th ng-repeat="item in yourList">{{ item.name }}</th>
</tr>
<tr>
<td>Price</td>
<td ng-repeat="item in yourList">{{ item.price }}</td>
</tr>
</table>
I'm trying to create a nested ng-repeat loop. It uses the groupBy and toArray filters from angular-filter.
The issue is that I have an editable input field in the nested array. Without implementing "track by" on the ng-repeats every time the value changes when typed it looses focus as described in this issue.
If I try to put a track by on the repeats it breaks and shows many fields with blank values. Is there any way to correctly implement track by in this situation so that the repeats display correctly and I can type into the input field without it losing focus?
Here is example, if you run it you will see as soon as you edit input you loose focus:
var app = angular.module('App', ['angular.filter']);
app.controller('MainCtrl', function() {
this.Parts = [{
Id: 1,
ShortDescription: "Premium Shocks",
SupplierSku: "ZXU3322",
SellPrice: 110,
SellPriceInclGst: 130,
ProfitExclGst: 10,
SupplierName: 'Super Sports',
Quantity: 3
}, {
Id: 2,
ShortDescription: "Spanner",
SupplierSku: "4444",
SellPrice: 44,
SellPriceInclGst: 130,
ProfitExclGst: 10,
SupplierName: 'Bobs Parts',
Quantity: 1
}, {
Id: 3,
ShortDescription: "Spark Plugs",
SupplierSku: "xxxxx",
SellPrice: 10,
SellPriceInclGst: 130,
ProfitExclGst: 10,
SupplierName: 'Bobs Parts',
Quantity: 5
}]
});
<html>
<head>
<script src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.15/angular.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/angular-filter/0.5.4/angular-filter.min.js"></script>
</head>
<body ng-app="App">
<table class="table" ng-controller='MainCtrl as main'>
<thead>
<tr>
<th>Short Descriptin</th>
<th>SKU</th>
<th>Qty</th>
<th>Unit Price</th>
<th>Total</th>
<th>Total + GST</th>
</tr>
</thead>
<tbody ng-repeat="supplier in main.Parts | groupBy:'SupplierName' | toArray:true | orderBy:'$key'">
<tr class="title-display-row">
<td colspan="6">{{ supplier.$key }}</td>
</tr>
<tr ng-repeat="item in supplier track by $index">
<td>{{ item.ShortDescription }} {{ key }}</td>
<td>{{ item.SupplierSku }}</td>
<td class="field-cell">
<div class="field-wrap">
<input type="text" name="quantity[$index]" ng-model="item.Quantity" />
</div>
</td>
<td>{{ item.SellPrice | currency }}</td>
<td>Total</td>
<td>Total-gst</td>
</tr>
</tbody>
</table>
</body>
</html>
Any suggestions greatly appreciated.
In the unlikely event someone has the same problem as this... the solution was to remove the toArray|true filter.
Then instead of accessing the supplier name with {{ supplier.$key }} I'm using {{ Supplier[0].SupplierName }}. Because each supplier in the loop is an array of items with the same supplier name so I can just take the first and use it.
I try to work with angular-sortable, but maybe I made something wrong because this code doesn't work.Where my mistake? All thead clickable, but it does sorting data in the table, just change css styles on click. Maybe I wrote wrong ts-criteria or wrong work with data?
My table:
<table ts-wrapper>
<thead>
<tr>
<th class="add">Add</th>
<th ts-criteria="population" ng-repeat="year in vm.years" ts-repeat>{{ year }}</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="city in vm.cities" ts-repeat>
<td >{{ city.name }}</td>
<td ng-repeat="population in city.population">{{ population }}</td>
</tr>
</tbody>
</table>
This is my controller:
(function () {
'use strict';
var app = angular.module("app",['tableSort']);
app.controller("TableController", TableController);
function TableController () {
var vm = this;
vm.years = ['2005', '2006', '2007', '2008', '2009', '2010', '2011', '2012', '2013', '2014'];
vm.cities = [
{
"name":"Москва",
'population':{
'2005': '7000000',
'2006':'7300000',
'2007':'7800000',
'2008':'8000000',
'2009':'8400000',
'2010':'8700000',
'2011':'9000000',
'2012':'9400000',
'2013':'9800000',
'2014':'10000000'
}
},
{
"name":"Санкт-Петербург",
'population':{
'2005':'6000000',
'2006':'6300000',
'2007':'6800000',
'2008':'7000000',
'2009':'7400000',
'2010':'7700000',
'2011':'8000000',
'2012':'8400000',
'2013':'8800000',
'2014':'9000000'
}
},
{
"name":"Калининград",
'population':{
'2005':'2000000',
'2006':'2300000',
'2007':'2800000',
'2008':'3000000',
'2009':'3400000',
'2010':'3700000',
'2011':'4000000',
'2012':'4400000',
'2013':'4800000',
'2014':'4900000'
}
},
{
"name":"Архангельск",
'population':{
'2005':'295000',
'2006':'300000',
'2007':'305000',
'2008':'308000',
'2009':'310000',
'2010':'315000',
'2011':'318000',
'2012':'324000',
'2013':'331000',
'2014':'341000'
}
},
{
"name":"Астрахань",
'population':{
'2005':'493000',
'2006':'497000',
'2007':'499000',
'2008':'502000',
'2009':'504000',
'2010':'507000',
'2011':'509000',
'2012':'513000',
'2013':'514000',
'2014':'520000'
}
},
{
"name":"Уфа",
'population':{
'2005':'1028000',
'2006':'1034000',
'2007':'1036000',
'2008':'1038000',
'2009':'1042000',
'2010':'1047000',
'2011':'1051000',
'2012':'1054000',
'2013':'1059000',
'2014':'1062000'
}
},
{
"name":"Белгород",
'population':{
'2005':'318000',
'2006':'321000',
'2007':'330000',
'2008':'333000',
'2009':'339000',
'2010':'342000',
'2011':'345000',
'2012':'350000',
'2013':'354000',
'2014':'356000'
}
},
{
"name":"Брянск",
'population':{
'2005':'381000',
'2006':'384000',
'2007':'390000',
'2008':'394000',
'2009':'397000',
'2010':'400000',
'2011':'402000',
'2012':'404000',
'2013':'413000',
'2014':'415000'
}
},
{
"name":"Улан-Удэ",
'population':{
'2005':'370000',
'2006':'372000',
'2007':'375000',
'2008':'379000',
'2009':'384000',
'2010':'391000',
'2011':'396000',
'2012':'397000',
'2013':'400000',
'2014':'404000'
}
},
{
"name":"Волгоград",
'population':{
'2005':'991000',
'2006':'995000',
'2007':'999000',
'2008':'1001000',
'2009':'1004000',
'2010':'1010000',
'2011':'1012000',
'2012':'1015000',
'2013':'1019000',
'2014':'1021000'
}
},
];
}
}());
[Answer updated to match your fiddle]
There are many many problems:
The worst is that the tablesorter does not handle criteria columns
with names that are numeric (such as a year). So they need to be
parseable only as strings. Like "y2010" for example.
The ts-criteria="population['year']" thing doesn't work. There is no such array.
It doesn't seem to like your "track by" directives.
It doesn't like ng-repeats in the data columns either, so I had to take out the population sub-object.
Also you are not specifying a filter for the ts-criteria, which will screw up your sorting since the population numbers will be sorted as Strings ("900" > "10000" for example....).
So basically tablesorter will only work if you follow the example code really close :-). Unless you start fixing those problems. There is a fiddle at http://jsfiddle.net/o15bLvb2/2/ which makes all of this work.
Your body becomes:
<body ng-app="app" ng-controller="TableController as vm">
<table cellpadding="10" cellspacing="10" ts-wrapper >
<thead>
<tr>
<th class="add" ts-criteria="add" ts-default>Add</th>
<th ts-criteria="y2005|parseInt">y2005</th>
<th ts-criteria="y2006|parseInt">y2006</th>
<th ts-criteria="y2007|parseInt">y2007</th>
<th ts-criteria="y2008|parseInt">y2008</th>
<th ts-criteria="y2009|parseInt">y2009</th>
<th ts-criteria="y2010|parseInt">y2010</th>
<th ts-criteria="y2011|parseInt">y2011</th>
<th ts-criteria="y2012|parseInt">y2012</th>
<th ts-criteria="y2013|parseInt">y2013</th>
<th ts-criteria="y2014|parseInt">y2014</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="city in vm.cities track by city.name" ts-repeat>
<td>{{ city.name }}</td>
<td>{{ city.y2005 }}</td>
<td>{{ city.y2006 }}</td>
<td>{{ city.y2007 }}</td>
<td>{{ city.y2008 }}</td>
<td>{{ city.y2009 }}</td>
<td>{{ city.y2010 }}</td>
<td>{{ city.y2011 }}</td>
<td>{{ city.y2012 }}</td>
<td>{{ city.y2013 }}</td>
<td>{{ city.y2014 }}</td>
</tr>
</tbody>
</table>
</body>
I have a dynamic dataset to present with Angular. In other words I do not have access to the column names returned until runtime.
I can present the column names as a header and the data itself with no problem. ng-repeat (or perhaps it's JS itself) though refuses to return the columns in the order they were created. You can see in the fiddle the columns are sorted so they appear "age name weight", I need them the way they came, "name age weight"
I created another array of the column names and their proper order ($scope.order) but I cannot seem to find a way to use that with Angular to sort the data.
Please give me a way to present this data in the original order.
I created a JSFiddle: http://jsfiddle.net/GE7SW/
Here's a simple scope that sets up the data:
function MainCtrl($scope) {
$scope.output = [
{
"name": "Tom",
"age": "25",
"weight" : 250
},
{
"name": "Allan",
"age": "28",
"weight" : 175
},
{
"name": "Sally",
"age": "35",
"weight" : 150
}
];
$scope.order = {
"name": 1,
"age": 2,
"weight" : 3
};
}
Here's the HTML:
<table ng-app ng-controller="MainCtrl">
<thead>
<tr>
<th ng-repeat="(key,value) in output.0">{{key}}</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="row in output">
<td ng-repeat="(key,value) in row">{{value}}</td>
</tr>
</tbody>
</table>
(Note the (key,value) in the last ng-repeat is needed by ng-class code I took out for this example.)
The properties order in JavaScript objects is never guaranteed. You need to use a list.
The only thing you need to do is convert $scope.order into an array:
$scope.order = [
"name",
"age",
"weight"
];
and use that inside the HTML like this:
<table ng-app ng-controller="MainCtrl">
<thead>
<tr>
<th ng-repeat="key in order">{{key}}</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="row in output">
<td ng-repeat="key in order">{{row[key]}}</td>
</tr>
</tbody>
</table>
Fiddle
Your updated fiddle here (click).
While the order of javascript objects is not guaranteed, this is likely to work in most or all cases. This is simply looping your objects into arrays. It might be a better approach, if possible, to have the data coming from the server in arrays, 1 that describes the structure (keys) and the other that just data sets of arrays.
$scope.getRow = function(row) {
var arr = [];
for (var k in row) {
if (k !== '$$hashKey') {
arr.push(row[k]);
}
}
return arr;
};
$scope.getKeys = function(row) {
var arr = [];
for (var k in row) {
if (k !== '$$hashKey') {
arr.push(k);
}
}
return arr;
};
the html:
<table ng-app ng-controller="MainCtrl">
<thead>
<tr>
<th ng-repeat="(key,value) in getKeys(output[0])">{{value}}</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="row in output">
<td ng-repeat="(key, value) in getRow(row)" ng-class="getKeys(output[0])[key]">{{value}}</td>
</tr>
</tbody>
</table>