Grid with different colours for each cell - angularjs

I'm new in AngularJS (1.6) and hope you can help me with this question.
I have a grid that grows the number of columns according to the selected date range. This table always has five rows below the header.
I need to create color conditions for each cell depending on the data base value. Something like validate my data before the grid, adding a status for each data, and apply a collor condition based on this status
Ex:
10/11 11/11 12/11 13/11
7% 8% 3% 9%
3% 2% 1% 4%
9% 7% 8% 3%
7% 8% 3% 9%
3% 2% 1% 4%
Controller
$scope.buscarDados = function (concessionaria, data_inicio, data_fim) {
$http({
method: 'POST',
data: { Concessionaria: concessionaria, DataInicio: data_inicio, DataFim: data_fim },
url: '/AnaliseDados/GerarJsonCabecalhoGrid'
})
.then(function (response) {
$scope.table_headers = response.data.table_headers;
}, function (error) {
console.log(error);
});
$http({
method: 'POST',
data: { Concessionaria: concessionaria, DataInicio: data_inicio, DataFim: data_fim },
url: '/AnaliseDados/buscaDadosPI'
})
.then(function (response) {
$scope.items = response.data.items;
}
)
};
View
<table class="table table-striped table-condensed table-hover">
<thead>
<tr>
<th ng-repeat="header in table_headers" class="{{header.name}}">
{{ header.name }}
</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="item in items">
<td ng-repeat="val in item">{{item[table_headers[$index].name]}}</td>
</tr>
</tbody>
</table>
JSON
$scope.table_headers = [
{ "name": "id"},
{ "name": "01/08" },
{ "name": "02/08" },
{ "name": "03/08" },
{ "name": "04/08" },
{ "name": "05/08" }
];
$scope.items = [
{ "id": 1, "01/08": 10, "02/08": 13, "03/08": 22, "04/08": 26, "05/08": 33 },
{ "id": 2, "01/08": 12, "02/08": 15, "03/08": 24, "04/08": 28, "05/08": 35 },
{ "id": 3, "01/08": 14, "02/08": 17, "03/08": 26, "04/08": 30, "05/08": 37 },
{ "id": 4, "01/08": 16, "02/08": 19, "03/08": 28, "04/08": 32, "05/08": 39 },
{ "id": 5, "01/08": 18, "02/08": 21, "03/08": 30, "04/08": 35, "05/08": 41 },
{ "id": 6, "01/08": 20, "02/08": 23, "03/08": 32, "04/08": 37, "05/08": 43 }
];
populated itens

Not sure if I understood what you need. For what I have understood I think something like this may help you
<div ng-controller="MyCtrl">
<table class="table table-striped table-condensed table-hover">
<thead>
<tr>
<th ng-repeat="header in table_headers" class="{{header.name}}">
{{ header.name }}
</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="item in items">
<td ng-repeat="val in item" ng-class="{'until-20' : item[table_headers[$index].name] <= 20, 'until-40' : item[table_headers[$index].name] > 20 && item[table_headers[$index].name] <= 40}">{{ item[table_headers[$index].name] }}</td>
</tr>
</tbody>
</table>
</div>
.until-20 {
background-color: red;
}
.until-40 {
background-color: yellow;
}
.until-60 {
background-color: green;
}
.until-80 {
background-color: blue;
}
.until-100 {
background-color: purple;
}
Obviously you must add remaining conditions.
Otherwise you can act more massively on css, like so:
<div ng-controller="MyCtrl">
<table class="table table-striped table-condensed table-hover">
<thead>
<tr>
<th ng-repeat="header in table_headers" class="{{header.name}}">
{{ header.name }}
</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="item in items">
<td ng-repeat="val in item" class="value-{{item[table_headers[$index].name]}}">{{ item[table_headers[$index].name] }}</td>
</tr>
</tbody>
</table>
</div>
.value-0, .value-1, .value-2, .value-3, .value-4, .value-5, .value-6, .value-7, .value-8, .value-9, .value-10, .value-11, .value-12, .value-13, .value-14, .value-15, .value-16, .value-17, .value-18, .value-19, .value-20 {
background-color: red;
}
.value-21, .value-22, .value-23, .value-24, .value-25, .value-26, .value-27, .value-28, .value-29, .value-30, .value-31, .value-32, .value-33, .value-34, .value-35, .value-36, .value-37, .value-38, .value-39, .value-40 {
background-color: green;
}
Hope that helps

You can create different columns with different styles and change their visibility according to your condition
<th class="style1" ng-show="condition = condition1">
{{ header.name }}
</th>
<th class="style2" ng-show="condition = condition2">
{{ header.name }}
</th>
<th class="style3" ng-show="condition = condition3">
{{ header.name }}
</th>
or you can use a custom filter
html
<th ng-repeat="header in table_headers | filter: filterStyle" class="{{header.style}}">
{{ header.name }}
</th>
js
$scope.filterStyle = function (item) {
if (item.condition == 'condition1') {
item.style = 'style1';
}
else if (item.condition == 'condition2') {
item.style = 'style2';
}
else if (item.condition == 'condition3') {
item.style = 'style3';
}
else {
item.style = 'default style';
}
return true;
};

I would use ngClass and write an expression or even invoke a function that return the color class name given the item value:
<td ng-repeat="val in item" ng-class={'color-1': val < 10, 'color-2': val >= 10}>

Related

Vue v-for nested array

I've got a nested array that I would like to display in a table. However, I can't get my nested array to show correctly.
My data set looks like this:
[
{
"dd":"February",
"md":[
{ "dag":"2020-02-01" },
{ "dag":"2020-02-02" },
{ "dag":"2020-02-03" }
]
},
{
"dd":"March",
"md":[
{ "dag":"2020-03-01" },
{ "dag":"2020-03-02" },
{ "dag":"2020-03-03" }
]
}
]
I would like a table which look like this.
| February | March |
| 2020-02-01 | 2020-03-01 |
| 2020-02-02 | 2020-03-02 |
| 2020-02-03 | 2020-03-03 |
I got this working, but it gives me 2 tables instead of one.
<template v-for="(md2, index) in md2s">
<table :key=index >
<thead >
<tr align="center">
<th style="width: 80px">{{md2}}</th>
</tr>
</thead>
<tr v-for="(date, index) in md2.md" :key=index>
<td align="center" >{{date.dag }}</td>
</tr>
</table>
</template>
All help is appreciated.
br. Erik
You could use a different way to create the loop (one table, multiple columns)
In this case, to populate each header with 'dd' and each column with md elements.
var data=[
{
"dd":"February",
"md":[
{
"dag":"2020-02-01"
},
{
"dag":"2020-02-02"
},
{
"dag":"2020-02-03"
}
]
},
{
"dd":"March",
"md":[
{
"dag":"2020-03-01"
},
{
"dag":"2020-03-02"
},
{
"dag":"2020-03-03"
}
]
}
];
new Vue({
el:'#app',
data:{
md2s: data
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.8/vue.js"></script>
<div id=app >
<table >
<thead >
<tr align="center">
<th v-for="(md2, index) in md2s" :key=index style="width: 80px">{{md2.dd}}</th>
</tr>
</thead>
<tbody>
<tr align="center">
<td v-for="(md2, index) in md2s" :key=index style="width: 80px">
<div v-for="(mdcol, col) in md2.md" :key=col>
{{mdcol.dag}}
</div>
</td>
</tr>
</tbody>
</table>
</div>
https://jsfiddle.net/bn5g1v09/1/
What you need is two diferent iterations. One for the header and another for the table body. For the header, all you need is to add the month name on order. The snippet shows with the computed property months how to do it. This completes the header iteration and the first.
The second one is a little more complex. You need to know beforehand how many lines there will be, for that I made a computed property maxLength that searches over each md and gives the greater one. Then for each row iterate over each month and then verify if the month has enough dates with v-if and if it does look up the desired date from the index and the nested data sctructure. That resumes the second iteration.
The below snippet is a working example with a more complex data showing what could happen with different md sizes and automatic month ordering.
var app = new Vue({
el: '#app',
data: () => ({
nested: [
{ "dd": "February",
"md": [{ "dag": "2020-02-01" },{ "dag": "2020-02-02" },{ "dag": "2020-02-03" },{ "dag": "2020-03-04" }]
},
{ "dd": "March",
"md": [{ "dag": "2020-03-01" },{ "dag": "2020-03-02" },{ "dag": "2020-03-03" }]
},
{ "dd": "January",
"md": [{ "dag": "2020-01-01" }]
}
]
}),
computed: {
staticMonths() {
return Array.from(Array(12),(e,i)=>new Date(25e8*++i).toLocaleString('en-US',{month: 'long'}));
},
months() {
return this.nested.map(item => item.dd).sort((a, b) => {
const A = this.staticMonths.indexOf(a);
const B = this.staticMonths.indexOf(b);
return A-B;
});
},
maxLength() {
return this.nested.reduce((accum, curr) => accum > curr.md.length ? accum : curr.md.length, 0);
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<table>
<thead>
<tr>
<th v-for="(item, index) in months">{{ item }}</th>
</tr>
</thead>
<tbody>
<tr v-for="index in maxLength">
<td v-for="item in months">
<span v-if="nested.find(nest => nest.dd === item).md.length > index-1">
{{nested.find(nest=>nest.dd===item).md[index-1].dag}}
</span>
</td>
</tr>
</tbody>
</table>
</div>

How to create subtotals in a ng-repeat in Angular JS

I'm just learning AngularJS and need to create the report below. I have all the detail lines working well but have no idea how to create the subtotal lines.
Detail lines...
<tr data-ng-repeat-start="t in testReferrers">
<td>{{t.ReferrerName}}</td>
<td>{{t.AddressLine1}}}</td>
<td>{{t.DatePlaced | date:'MM/dd/yyyy'}}</td>
<td>{{t.InvoiceNumber }}</td>
<td>{{t.InvoiceAmountLessDiscount | currency : $ : 2 }}</td>
</tr>
My first attempt at subtotal line, but I don't know how to calculate {{subTotal}} and how to control when this row shows up. I need a grouping and group footer capability but don't know how to do that in AngularJS. I was going to use JQuery to find the subTotalRow and either show or hide...
<tr id="subtotalRow" data-ng-repeat-end style="display:none">
<td colspan=3></td>
<td style="border-top: solid 1px #000000">Total:</td>
<td style="border-top: solid 1px #000000">{{subTotal | currency : $ : 2 }}</td>
</tr>
Desired output...
angular.module('app', []).controller('ctrl', function($scope){
$scope.data = [
{Referrer: 'Henry', Amount: 20, Location: 'NY'},
{Referrer: 'Tom', Amount: 10, Location: 'London'},
{Referrer: 'Sam', Amount: 10, Location: 'Paris'},
{Referrer: 'Henry', Amount: 10, Location: 'NY'},
{Referrer: 'Tom', Amount: 20, Location: 'London'},
{Referrer: 'Henry', Amount: 30, Location: 'NY'}
];
$scope.sum = function(name){
return $scope.data.filter(function(x) { return x.Referrer == name; })
.map(function(x) { return x.Amount; }).reduce(function(a, b) { return a + b; });
}
})
table, th, td {
border: 1px solid black;
border-collapse: collapse;
}
.totalRow{
border-style: solid;
}
.total{
text-align: right;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.5/angular.min.js">
</script>
<div ng-app='app' ng-controller='ctrl'>
<table>
<thead>
<tr>
<th>Referrer</th>
<th>Location</th>
<th>Amount</th>
</tr>
</thead>
<tbody>
<tr ng-init='next = $index + 1' ng-repeat-start='item in dataSorted = (data | orderBy : "Referrer")'>
<td>{{item.Referrer}}</td>
<td>{{item.Location}}</td>
<td>{{item.Amount}}</td>
</tr>
<tr class='totalRow' ng-repeat-end ng-if='!dataSorted[next] || (dataSorted[next].Referrer != item.Referrer)'>
<td colspan='2' class='total'>Total:</td>
<td>{{sum(item.Referrer)}}</td>
</tr>
</tbody>
</table>
</div>

Creating dynamic table using AngularJS and restful api

I'm trying to create a table using Quandl restful api along with AngularJS. While table headers created well table rows aren't filled with data at all, there are only empty rows.
Here is my controller:
angular.module('stockControllers', [])
.controller('stockController', function($scope, $http){
var results = {};
$http.get('https://www.quandl.com/api/v3/datasets/WIKI/FB.json?start_date=2017-11-01&api_key=3pg7TVEyogz6D6FXhf5g').
then(function(response) {
$scope.resulting = response.data;
console.log($scope.resulting);
});
});
HTML code:
<div ng-controller="stockController">
<div class='page-header'>
<h1> {{resulting.dataset.name}} </h1>
<p> Note: showing only OHLC data </p>
</div>
<table class="table table-striped">
<tr>
<th>{{resulting.dataset.column_names[0]}}</th>
<th>{{resulting.dataset.column_names[1]}}</th>
<th>{{resulting.dataset.column_names[2]}}</th>
<th>{{resulting.dataset.column_names[3]}}</th>
<th>{{resulting.dataset.column_names[4]}}</th>
</tr>
<tr ng-repeat="row in resulting.dataset.data">
<td>{{resulting.dataset.data[row][0]}}</td>
<td>{{resulting.dataset.data[row][1]}}</td>
<td>{{resulting.dataset.data[row][2]}}</td>
<td>{{resulting.dataset.data[row][3]}}</td>
<td>{{resulting.dataset.data[row][4]}}</td>
</tr>
</table>
</div>
And api response fragment which I want to use:
"dataset": {
"column_names": ["Date","Open","High","Low","Close","Volume","Ex-Dividend","Split Ratio","Adj. Open","Adj. High","Adj. Low","Adj. Close","Adj. Volume"],
"data": [["2017-11-13",
177.5,
179.04,
177.3,
178.77,
9431449,
0,
1,
177.5,
179.04,
177.3,
178.77,
9431449 ],,
[
"2017-11-10",
178.35,
179.0999,
177.96,
178.46,
10933405,
0,
1,
178.35,
179.0999,
177.96,
178.46,
10933405 ],,
angular.module('app', []).controller('ctrl', function($scope) {
$scope.resulting = {
dataset: {
column_names: ["Date", "Open", "High", "Low", "Close", "Volume", "Ex-Dividend", "Split Ratio", "Adj. Open", "Adj. High", "Adj. Low", "Adj. Close", "Adj. Volume"],
data: [
["2017-11-13",
177.5,
179.04,
177.3,
178.77,
9431449,
0,
1,
177.5,
179.04,
177.3,
178.77,
9431449
],
[
"2017-11-10",
178.35,
179.0999,
177.96,
178.46,
10933405,
0,
1,
178.35,
179.0999,
177.96,
178.46,
10933405
]
]
}
}
});
table,
th,
td {
border: 1px solid black;
border-collapse: collapse;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<table ng-app='app' ng-controller='ctrl'>
<thead>
<tr>
<th ng-repeat='head in resulting.dataset.column_names' ng-if='$index < 5'>{{head}}</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="row in resulting.dataset.data">
<td ng-repeat='val in row track by $index' ng-if='$index < 5'>{{val}}</td>
</tr>
</tbody>
</table>

dataTable columnFilter dropdown boxes won't appear

I'm having problems getting my dataTable columnFilter select boxes to appear.
I have similar code blocks working on several other pages within the application, but for some reason, the <select> dropdown boxes won't appear. I have validated that the list of values (statusValues and seasonValues) have the correct values in the array and there are no errors in the console.
The column count is correct (I had that problem before). I'm using dataTables 1.10.9.
What am I missing?
Here's my code:
#using ApolloAMS.Business.Models;
#model List<Tournament>
#{
ViewBag.Title = "Manage Tournaments";
ViewBag.TournamentName = "";
List<Season> seasons = ViewBag.Seasons;
}
<div class="row" style="margin-bottom: 20px;">
<div class="col-md-2">
<span style="float: left; font-weight: bold;">Tournament Status:</span>
<span style="float: left; width: 100%;" id="statusFilter" class="filter"></span>
</div>
<div class="col-md-2">
<span style="float: left; font-weight: bold;">Season:</span>
<span style="float: left; width: 100%;" id="seasonFilter" class="filter"></span>
</div>
</div>
<table id="tblData" class="table table-bordered table-hover dataTable">
<thead>
<tr>
<th>Action</th>
<th>Name</th>
<th>Status</th>
<th>Season</th>
<th>Dates</th>
<th># Flights /# Lanes / Max Shooters</th>
</tr>
</thead>
<tbody>
#foreach (Tournament tourn in Model)
{
Season season = seasons.Where(s => s.ID.Equals(tourn.SeasonID)).FirstOrDefault();
<tr>
<td>
#{Html.RenderPartial("TournamentActions", tourn.ID);}
</td>
<td>#tourn.Name</td>
<td><span class="statusCell">#tourn.TournStatusName</span></td>
<td><span class="seasonCell">#season.Name</span></td>
<td>#tourn.DateStart.ToShortDateString() - #tourn.DateEnd.ToShortDateString()</td>
<td>#tourn.NumberOfFlights / #tourn.NumberOfLanes / #tourn.MaxShooters</td>
</tr>
}
</tbody>
</table>
<br />
<br />
<br />
<br />
<br />
<br />
<br />
#section Scripts
{
<script type="text/javascript">
var statusValues = [];
var seasonValues = [];
$('.statusCell').each(function () {
var found = false;
var text = $(this).text();
for (i = 0; i < statusValues.length; i++) {
if (statusValues[i] == text) {
found = true;
break;
}
}
if (!found) {
statusValues.push(text);
}
});
$('.seasonCell').each(function () {
var found = false;
var text = $(this).text();
for (i = 0; i < seasonValues.length; i++) {
if (seasonValues[i] == text) {
found = true;
break;
}
}
if (!found) {
seasonValues.push(text);
}
});
statusValues.sort();
seasonValues.sort();
$("#tblData").dataTable(
{
"aLengthMenu": [[10, 25, -1], [10, 25, "All"]]
, "iDisplayLength": -1
, "scrollX": true
, "stateSave": true
, "oLanguage": {"sSearch": "Search: "}
, "order": [[4, "desc"]]
}).columnFilter({
aoColumns: [
null,
null,
{ type: "select", values: statusValues, sSelector: "#statusFilter" },
{ type: "select", values: seasonValues, sSelector: "#seasonFilter" },
null,
null,
]
});
//addl layout/config for datatable
$('input[type=search]').css("background-color", "yellow");
$('input[type=search]').css("font-weight", "bold");
$('input[type=search]').css("font-size", "large");
$('#tblData_filter label').css("font-size", "large");
$('#tblData_filter label').css("font-weight", "bold");
</script>
}
What am I missing? Clearly, my brain is what's missing. Gotta have the footer elements with matching columns.
<tfoot>
<tr>
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
</tr>
</tfoot>
Correct you need to have the <tfoot></tfoot> with matching columns. If you have the names of the columns in the <thead></thead> it might be helpful to have the names also in the <tfoot></tfoot>.
And since you have solved your problem please mark your answer as correct so that everyone can see that the question has an answer.

Angular: draw a table from json map

I try to create a table like Full Tilt Payout Structure. I decided to create the next map:
$scope.payoutStructure = {
'2-4': {
1: 100,
2: 0,
3: 0,
4: 0,
5: 0,
6: 0,
},
'6-7': {
1: 65,
2: 35,
3: 0,
4: 0,
5: 0,
6: 0,
}
}
and so on...
But I can't figure out how to render it. If i'm not mistaken, at first I have to render headers like that:
<thead>
<tr>
<th><strong>Position \ Entries</strong></th>
<th ng-repeat="key in payoutStructure.keys()">{{key}}</th> //I'm not sure about .keys(), because they are not render in order as I know
</tr>
</thead>
But I can't get how to render tbody. It seems like I have to use an array instead of a map but I want to get value by keys like:
{{payoutStructure[entries]['1']}}
1) header you should render like
<tr>
<th ng-repeat="(key,value) in payoutStructure">{{key}}</th>
</tr>
2)
as for tbody - it it rendered by rows (not by columns), so your structure
should follow this structure.
It can be smth like this:
$scope.payoutStructure = ['2-4','6-7','8-9', '10-18', '18-45'];
$scope.payoutData = [
[100, 65, 50, 40, 38],
[0, 35,30,30,25]
]
<table class="table">
<tr>
<th ng-repeat="header in payoutStructure">{{header}}</th>
</tr>
<tr ng-repeat="row in payoutData">
<td ng-repeat="value in row track by $index" >{{value}} </td>
</tr>
</table>
Following will works for your data structure:
<table class="table">
<thead><tr>
<th>Finishing Position</th>
<th ng-repeat="(key, value) in payoutStructure">{{key}}</th>
</tr></thead>
<tbody>
<tr ng-repeat="key in payoutStructure['2-4']">
<th scope="row">{{$index +1}}</th>
<td>{{payoutStructure['2-4'][$index+1]}}</td>
<td>{{payoutStructure['6-7'][$index+1]}}</td>
</tr>
</tbody>
</table>
But better one if you change data structure as following:
(function(angular) {
'use strict';
angular.module('ngRepeat', [])
.controller('repeatController', function($scope) {
$scope.payouts = {
'2-4': [100],
'6-7': [65, 35],
'8-5': [50, 30, 20],
'10-18': [40, 30, 20, 10],
'18-45': [38, 25, 16, 10, 6, 5]
};
$scope.maxArray = [];
angular.forEach($scope.payouts, function(value, key) {
if (value.length > $scope.maxArray.length)
$scope.maxArray = value;
});
});
})(window.angular);
Here is $scope.maxArray where we write payout with max data array length. And now you can output it with ng-repeat:
<table class="table">
<thead><tr>
<th>Finishing Position</th>
<th ng-repeat="(key, value) in payouts">
{{key}}
</th>
</tr></thead>
<tbody>
<tr ng-repeat="key in maxArray track by $index">
<th scope="row">{{$index + 1}}</th>
<td ng-repeat="payout in payouts">
{{payout[$parent.$index]}}
</td>
</tr>
</tbody>
</table>
Result on plunker:
http://plnkr.co/edit/n5BfCtqjUKJ7LxvtxIFp?p=preview
And official API docs for ngRepeat directive:
https://docs.angularjs.org/api/ng/directive/ngRepeat

Resources