Angular 7 mat-table with array in array - arrays

I'm using Angular 7 and using mat-table.
https://material.angular.io/components/table/overview
However, all examples I can find use a simple array to create the mat-table from. My array (see below) has an array in an array. I need to iterate over the Results array and then the "line_items" array. But can't find a single example of how this is done?
Component.ts
<mat-table [dataSource]="dataSource" matSort (matSortChange)="sortChanged($event)">
<ng-container matColumnDef="line_items">
<mat-header-cell *matHeaderCellDef mat-sort-header>line_items</mat-header-cell>
<mat-cell *matCellDef="let element">{{element.line_items}}</mat-cell>
</ng-container>
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef mat-sort-header>Name</mat-header-cell>
<mat-cell *matCellDef="let element">{{element.name}}</mat-cell>
</ng-container>
<ng-container matColumnDef="number">
<mat-header-cell *matHeaderCellDef mat-sort-header>Number</mat-header-cell>
<mat-cell *matCellDef="let element">{{element.number}}</mat-cell>
</ng-container>
<ng-container matColumnDef="category">
<mat-header-cell *matHeaderCellDef mat-sort-header>Category</mat-header-cell>
<mat-cell *matCellDef="let element">{{element.category}}</mat-cell>
</ng-container>
<ng-container matColumnDef="original_budget">
<mat-header-cell *matHeaderCellDef mat-sort-header>Original Budget</mat-header-cell>
<mat-cell *matCellDef="let element">{{element.original_budget}}</mat-cell>
</ng-container>
<ng-container matColumnDef="approved_cos">
<mat-header-cell *matHeaderCellDef mat-sort-header>Approved Cos</mat-header-cell>
<mat-cell *matCellDef="let element">{{element.approved_cos}}</mat-cell>
</ng-container>
<ng-container matColumnDef="revised_budget">
<mat-header-cell *matHeaderCellDef mat-sort-header>Revised Budget</mat-header-cell>
<mat-cell *matCellDef="let element">{{element.revised_budget}}</mat-cell>
</ng-container>
<ng-container matColumnDef="pending_budget_changes">
<mat-header-cell *matHeaderCellDef mat-sort-header>Pending Budget Changes</mat-header-cell>
<mat-cell *matCellDef="let element">{{element.pending_budget_changes}}</mat-cell>
</ng-container>
<ng-container matColumnDef="projected_budget">
<mat-header-cell *matHeaderCellDef mat-sort-header>Projected Budget</mat-header-cell>
<mat-cell *matCellDef="let element">{{element.projected_budget}}</mat-cell>
</ng-container>
<ng-container matColumnDef="loading">
<mat-footer-cell *matFooterCellDef colspan="6">
Loading data...
</mat-footer-cell>
</ng-container>
<ng-container matColumnDef="noData">
<mat-footer-cell *matFooterCellDef colspan="6">
No data.
</mat-footer-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns;" (click)="selectRow(row, $event)" (dblclick)="onEdit(row, $event)"></mat-row>
<mat-footer-row *matFooterRowDef="['loading']" [ngClass]="{'hide':dataSource!=null}"></mat-footer-row>
<mat-footer-row *matFooterRowDef="['noData']" [ngClass]="{'hide':!(dataSource!=null && dataSource.data.length==0)}"></mat-footer-row>
</mat-table>
Array
{
"results": [
{
"name": "General Requirements",
"id": "1",
"line_items": [
{
"name": "Project Manager",
"number": "442",
"category": "L",
"original_budget": 30000,
"approved_cos": 0,
"revised_budget": 30000,
"pending_budget_changes": 0,
"projected_budget": 30000,
"committed_costs": 0,
"direct_costs": 0,
"pending_costs_changes": 0,
"projected_costs": 0,
"forecast_to_complete": 30000,
"estimated_cost_at_completion": 30000,
"projected_over_under": 0
},
{
"name": "Project Engineer",
"number": "564",
"category": "L",
"original_budget": 17000,
"approved_cos": 0,
"revised_budget": 17000,
"pending_budget_changes": 0,
"projected_budget": 17000,
"committed_costs": 0,
"direct_costs": 0,
"pending_costs_changes": 0,
"projected_costs": 0,
"forecast_to_complete": 17000,
"estimated_cost_at_completion": 17000,
"projected_over_under": 0
},
{
"name": "Superintendent",
"number": "766",
"category": "L",
"original_budget": 55000,
"approved_cos": 0,
"revised_budget": 55000,
"pending_budget_changes": 0,
"projected_budget": 55000,
"committed_costs": 0,
"direct_costs": 0,
"pending_costs_changes": 0,
"projected_costs": 0,
"forecast_to_complete": 55000,
"estimated_cost_at_completion": 55000,
"projected_over_under": 0
},
{
"name": "Project Coordinator",
"number": "876",
"category": "L",
"original_budget": 5000,
"approved_cos": 0,
"revised_budget": 5000,
"pending_budget_changes": 0,
"projected_budget": 5000,
"committed_costs": 0,
"direct_costs": 0,
"pending_costs_changes": 0,
"projected_costs": 0,
"forecast_to_complete": 5000,
"estimated_cost_at_completion": 5000,
"projected_over_under": 0
}
]
},
{
"name": "Doors And Windows",
"id": "2",
"line_items": [
{
"name": "Doors",
"number": "600",
"category": "O",
"original_budget": 2000,
"approved_cos": 0,
"revised_budget": 2000,
"pending_budget_changes": 0,
"projected_budget": 2000,
"committed_costs": 0,
"direct_costs": 0,
"pending_costs_changes": 0,
"projected_costs": 0,
"forecast_to_complete": 2000,
"estimated_cost_at_completion": 2000,
"projected_over_under": 0
},
{
"name": "Doors",
"number": "600",
"category": "S",
"original_budget": 67000,
"approved_cos": 0,
"revised_budget": 67000,
"pending_budget_changes": 0,
"projected_budget": 67000,
"committed_costs": 0,
"direct_costs": 0,
"pending_costs_changes": 0,
"projected_costs": 0,
"forecast_to_complete": 67000,
"estimated_cost_at_completion": 67000,
"projected_over_under": 0
}
]
},
{
"name": "Finishes",
"id": "3",
"line_items": [
{
"name": "Kitchen Sink",
"number": "800",
"category": "O",
"original_budget": 5000,
"approved_cos": 0,
"revised_budget": 5000,
"pending_budget_changes": 0,
"projected_budget": 5000,
"committed_costs": 0,
"direct_costs": 0,
"pending_costs_changes": 0,
"projected_costs": 0,
"forecast_to_complete": 5000,
"estimated_cost_at_completion": 5000,
"projected_over_under": 0
}
]
}
]
}
UPDATE
I tried the below, hoping it would work, but nope...
<ng-container *ngFor="let budget of budgets">
<ng-container *ngFor="let item of budget.line_items">
{{item | json}}
<mat-table [dataSource]="item" matSort (matSortChange)="sortChanged($event)">

Based on the information provided I assume you are trying to have Mat-Table and a Nested Mat-Table for each of the rows in the parent table. This can be archived below. I have created a simple stackblitz sample with small data set similar to yours. In provided sample data set by myself addresses refer to your examples line_items attribute.
Please find the working sample stackblitz here.
Please find the code below :
component.ts :
import { Component, ViewChild, ViewChildren, QueryList, ChangeDetectorRef } from '#angular/core';
import { animate, state, style, transition, trigger } from '#angular/animations';
import { MatSort } from '#angular/material/sort';
import { MatTableDataSource, MatTable } from '#angular/material/table';
/**
* #title Table with expandable rows
*/
#Component({
selector: 'table-expandable-rows-example',
styleUrls: ['table-expandable-rows-example.css'],
templateUrl: 'table-expandable-rows-example.html',
animations: [
trigger('detailExpand', [
state('collapsed', style({ height: '0px', minHeight: '0' })),
state('expanded', style({ height: '*' })),
transition('expanded <=> collapsed', animate('225ms cubic-bezier(0.4, 0.0, 0.2, 1)')),
]),
],
})
export class TableExpandableRowsExample {
#ViewChild('outerSort', { static: true }) sort: MatSort;
#ViewChildren('innerSort') innerSort: QueryList<MatSort>;
#ViewChildren('innerTables') innerTables: QueryList<MatTable<Address>>;
dataSource: MatTableDataSource<User>;
usersData: User[] = [];
columnsToDisplay = ['name', 'email', 'phone'];
innerDisplayedColumns = ['street', 'zipCode', 'city'];
expandedElement: User | null;
constructor(
private cd: ChangeDetectorRef
) { }
ngOnInit() {
USERS.forEach(user => {
if (user.addresses && Array.isArray(user.addresses) && user.addresses.length) {
this.usersData = [...this.usersData, {...user, addresses: new MatTableDataSource(user.addresses)}];
} else {
this.usersData = [...this.usersData, user];
}
});
this.dataSource = new MatTableDataSource(this.usersData);
this.dataSource.sort = this.sort;
}
toggleRow(element: User) {
element.addresses && (element.addresses as MatTableDataSource<Address>).data.length ? (this.expandedElement = this.expandedElement === element ? null : element) : null;
this.cd.detectChanges();
this.innerTables.forEach((table, index) => (table.dataSource as MatTableDataSource<Address>).sort = this.innerSort.toArray()[index]);
}
applyFilter(filterValue: string) {
this.innerTables.forEach((table, index) => (table.dataSource as MatTableDataSource<Address>).filter = filterValue.trim().toLowerCase());
}
}
export interface User {
name: string;
email: string;
phone: string;
addresses?: Address[] | MatTableDataSource<Address>;
}
export interface Address {
street: string;
zipCode: string;
city: string;
}
export interface UserDataSource {
name: string;
email: string;
phone: string;
addresses?: MatTableDataSource<Address>;
}
const USERS: User[] = [
{
name: "Mason",
email: "mason#test.com",
phone: "9864785214",
addresses: [
{
street: "Street 1",
zipCode: "78542",
city: "Kansas"
},
{
street: "Street 2",
zipCode: "78554",
city: "Texas"
}
]
},
{
name: "Eugene",
email: "eugene#test.com",
phone: "8786541234",
},
{
name: "Jason",
email: "jason#test.com",
phone: "7856452187",
addresses: [
{
street: "Street 5",
zipCode: "23547",
city: "Utah"
},
{
street: "Street 5",
zipCode: "23547",
city: "Ohio"
}
]
}
];
component.html :
<table mat-table #outerSort="matSort" [dataSource]="dataSource" multiTemplateDataRows class="mat-elevation-z8" matSort>
<ng-container matColumnDef="{{column}}" *ngFor="let column of columnsToDisplay">
<th mat-header-cell *matHeaderCellDef mat-sort-header> {{column}} </th>
<td mat-cell *matCellDef="let element"> {{element[column]}} </td>
</ng-container>
<!-- Expanded Content Column - The detail row is made up of this one column that spans across all columns -->
<ng-container matColumnDef="expandedDetail">
<td mat-cell *matCellDef="let element" [attr.colspan]="columnsToDisplay.length">
<div class="example-element-detail" *ngIf="element.addresses?.data.length" [#detailExpand]="element == expandedElement ? 'expanded' : 'collapsed'">
<div class="inner-table mat-elevation-z8" *ngIf="expandedElement">
<mat-form-field>
<input matInput (keyup)="applyFilter($event.target.value)" placeholder="Filter">
</mat-form-field>
<table #innerTables mat-table #innerSort="matSort" [dataSource]="element.addresses" matSort>
<ng-container matColumnDef="{{innerColumn}}" *ngFor="let innerColumn of innerDisplayedColumns">
<th mat-header-cell *matHeaderCellDef mat-sort-header> {{innerColumn}} </th>
<td mat-cell *matCellDef="let element"> {{element[innerColumn]}} </td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="innerDisplayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: innerDisplayedColumns;"></tr>
</table>
</div>
</div>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="columnsToDisplay"></tr>
<tr mat-row *matRowDef="let element; columns: columnsToDisplay;" [class.example-element-row]="element.addresses?.data.length"
[class.example-expanded-row]="expandedElement === element" (click)="toggleRow(element)">
</tr>
<tr mat-row *matRowDef="let row; columns: ['expandedDetail']" class="example-detail-row"></tr>
</table>

Another approach can be use a single table. You create an array like
dataExpanded=this.data.results.reduce((a:any,b:any)=>{
return a.concat({name:b.name,id:b.id,number: "",category: "O",original_budget: 0,approved_cos: 0,revised_budget:0,pending_budget_changes: 0,projected_budget: 0,committed_costs: 0,direct_costs: 0,pending_costs_changes: 0,projected_costs: 0,forecast_to_complete: 0,estimated_cost_at_completion: 0,projected_over_under:0
},...b.line_items.map((x:any)=>({id:0,...x})))
},[])
And a table like
<table mat-table [dataSource]="dataExpanded" class="mat-elevation-z8">
<ng-container *ngFor="let column of displayedColumns;let i=index" [matColumnDef]="column">
<th mat-header-cell *matHeaderCellDef>{{header[i]}}</th>
<ng-container *matCellDef="let element">
<td class="header" mat-cell [attr.colspan]="15" *ngIf="element.id && column=='name'">
{{element.name}}
</td>
<ng-container *ngIf="!element.id">
<td *ngIf="column!='name'" mat-cell > {{element[column]}} </td>
<td *ngIf="column=='name'" mat-cell > {{element.number}} - {{element.name}} </td>
</ng-container>
</ng-container>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
See stackblitz

Related

Item Array as Datasource for NgFor

Just want to ask if is it possible to search an item in an array of objects and use it as datasource for my angular table? Can you share the syntax please?
Basically, i have an array of objects consisting of Id and its json file. Populate its data. Look for an item that matches the it, and use it as datasource in a ngfor grid.
I have the following code, but it returns compilation error.
Thanks
ts file
jsonData: Array<{ id: string, json: object }> = [];
ngOnInit(): void {
let json= [
{
"Id": "1",
"Col1": "val11",
"Col2": "val12
},
{
"Id": "2",
"Col1": "val21",
"Col2": "val22
}
]
this.jsonData.push({ id: "100", json: json });
}
html file
<ng-container *ngFor="let row of this.jsonData.find(e => e.id === "101").json;let i=row.Id">
row.Col1 //etc..
</ng-container>
I Have used a different approach check if this helps you out . I am filtering data from the constructer itself (ts file)
here is the code link https://stackblitz.com/edit/angular-wn7vwb?file=app%2Ftable-basic-example.ts
HTML
<table mat-table [dataSource]="dataSource" class="mat-elevation-z8">
<!-- Position Column -->
<ng-container matColumnDef="position">
<th mat-header-cell *matHeaderCellDef> No. </th>
<td mat-cell *matCellDef="let element"> {{element.position}} </td>
</ng-container>
<!-- Name Column -->
<ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef> Name </th>
<td mat-cell *matCellDef="let element"> {{element.name}} </td>
</ng-container>
<!-- Weight Column -->
<ng-container matColumnDef="weight">
<th mat-header-cell *matHeaderCellDef> Weight </th>
<td mat-cell *matCellDef="let element"> {{element.weight}} </td>
</ng-container>
<!-- Symbol Column -->
<ng-container matColumnDef="symbol">
<th mat-header-cell *matHeaderCellDef> Symbol </th>
<td mat-cell *matCellDef="let element"> {{element.symbol}} </td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
ts
import { Component } from '#angular/core';
const ELEMENT_DATA: PeriodicElement[] = [
{ position: 1, name: 'Hydrogen', weight: 1.0079, symbol: 'H' },
{ position: 2, name: 'Helium', weight: 4.0026, symbol: 'He' },
{ position: 3, name: 'Lithium', weight: 6.941, symbol: 'Li' },
{ position: 4, name: 'Beryllium', weight: 9.0122, symbol: 'Be' },
{ position: 5, name: 'Boron', weight: 10.811, symbol: 'B' },
{ position: 6, name: 'Carbon', weight: 12.0107, symbol: 'C' },
{ position: 7, name: 'Nitrogen', weight: 14.0067, symbol: 'N' },
{ position: 8, name: 'Oxygen', weight: 15.9994, symbol: 'O' },
{ position: 9, name: 'Fluorine', weight: 18.9984, symbol: 'F' },
{ position: 10, name: 'Neon', weight: 20.1797, symbol: 'Ne' },
];
/**
* #title Basic use of `<table mat-table>`
*/
#Component({
selector: 'table-basic-example',
styleUrls: ['table-basic-example.css'],
templateUrl: 'table-basic-example.html',
})
export class TableBasicExample {
displayedColumns = ['position', 'name', 'weight', 'symbol'];
dataSource = ELEMENT_DATA;
constructor() {
this.dataSource = this.dataSource.filter((res) => res.name == 'Helium');
}
}
export interface PeriodicElement {
name: string;
position: number;
weight: number;
symbol: string;
}

Nested ng-repeat has duplicate values

I am trying to fetch a report using Angular JS,
<tbody ng-repeat="p in GettingBillingPage track by $index " ng-init="idx = $index">
<tr>
<td><input type="button" class="btn btn-primary waves-effect"
value="Cancel" ng-click="GetBillDetails(idx)" />
</td>
<td>{{p.BillNo}}</td>
<td>{{p.FinalTotal | number:2}}</td>
<td>{{p.Name}}</td>
<td>{{p.purchaseDate |date}}</td>
<td>
<table cellpadding="0" cellspacing="0" class="table table-bordered">
<tr>
<th>Product Name</th>
<th>Quantity</th>
<th>Rate</th>
</tr>
<tbody ng-repeat="q in GettingBillingPage " ng-if="q.BillNo == p.BillNo">
<tr>
<td>{{q.ProductName}}</td>
<td>{{q.quantity}}</td>
<td>{{q.Rate | number:2}}</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
Even when both the ng-repeat is refering to a single Array, the billno repeats based on the number of items sold
Example of the Output Table
How to avoid repetition of bill no and hence the list of products
you need to print out unique values in the outer ng-repeat; This can be done with a custom filter...
var app = angular.module("myApp", []);
app.controller("myCtrl", function($scope) {
$scope.GettingBillingPage = [{
"BillNo": 1,
"FinalTotal": 203,
"Name": "test name 1",
"purchaseDate": '13',
"ProductName": "abc 1",
"quantity": 9,
"Rate": 12
},
{
"BillNo": 1,
"FinalTotal": 203,
"Name": "test name 1",
"purchaseDate": '13',
"ProductName": "abc 2",
"quantity": 9,
"Rate": 22
},
{
"BillNo": 2,
"FinalTotal": 421,
"Name": "test name 2",
"purchaseDate": '24',
"ProductName": "def",
"quantity": 9,
"Rate": 12
},
{
"BillNo": 3,
"FinalTotal": 625,
"Name": "test name 3",
"purchaseDate": '72',
"ProductName": "xyz 1",
"quantity": 9,
"Rate": 12
},
{
"BillNo": 3,
"FinalTotal": 625,
"Name": "test name 3",
"purchaseDate": '72',
"ProductName": "xyz 2",
"quantity": 9,
"Rate": 12
},
{
"BillNo": 3,
"FinalTotal": 625,
"Name": "test name 3",
"purchaseDate": '72',
"ProductName": "xyz 3",
"quantity": 9,
"Rate": 12
},
{
"BillNo": 4,
"FinalTotal": 928,
"Name": "test name 4",
"purchaseDate": '96',
"ProductName": "ghi",
"quantity": 9,
"Rate": 12
},
];
});
app.filter('unique', function() {
return function(collection, keyname) {
var output = [],
keys = [];
angular.forEach(collection, function(item) {
var key = item[keyname];
if (keys.indexOf(key) === -1) {
keys.push(key);
output.push(item);
}
});
return output;
};
});
td{border:0.5px dotted blue; padding:0 5px;}
table{border:1px solid red; margin:10px;}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.9/angular.min.js"></script>
<div ng-app="myApp" ng-controller="myCtrl">
<table>
<tbody ng-repeat="p in GettingBillingPage | unique : 'BillNo' ">
<tr>
<td>{{p.BillNo}}</td>
<td>{{p.FinalTotal | number:2}}</td>
<td>{{p.Name}}</td>
<td>{{p.purchaseDate |date}}</td>
<td>
<table>
<tbody ng-repeat="q in GettingBillingPage" ng-if="q.BillNo == p.BillNo">
<tr>
<td>{{q.ProductName}}</td>
<td>{{q.quantity}}</td>
<td>{{q.Rate | number:2}}</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
</div>

Grid with different colours for each cell

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}>

How to print data in Tabular format from this given JSON

I am trying to print the data under tabular format .
The data which is present under "properties" (ApprovalStatusShrtStrngVal and FluidCodeShrtStrngVal)
I have tried as
<div ng-app="myapp" ng-controller="FirstCtrl">
<table border="1">
<tr>
<th ng-repeat="(key, val) in collectioninfo.records.properties">{{ key }}</th>
</tr>
<tr ng-repeat="row in collectioninfo">
<td ng-repeat="column in row">
{{ column }}
</td>
</tr>
</table>
</div>
JSON is
{
"records": [{
"keys": ["n"],
"length": 1,
"_fields": [{
"identity": {
"low": 1128,
"high": 0
},
"labels": ["TestLabel"],
"properties": {
"ApprovalStatusShrtStrngVal": "Working",
"FluidCodeShrtStrngVal": "P"
}
}],
"_fieldLookup": {
"n": 0
}
}, {
"keys": ["n"],
"length": 1,
"_fields": [{
"identity": {
"low": 1129,
"high": 0
},
"labels": ["TestLabel"],
"properties": {
"ApprovalStatusShrtStrngVal": "Working",
"FluidCodeShrtStrngVal": "P"
}
}],
"_fieldLookup": {
"n": 0
}
}],
"summary": {
"statement": {
"text": "MATCH (n:TestLabel) RETURN n LIMIT 25",
"parameters": {}
},
"statementType": "r",
"counters": {
"_stats": {
"constraintsRemoved": 0
}
},
"updateStatistics": {
"_stats": {
"constraintsRemoved": 0
}
},
"plan": false,
"profile": false,
"notifications": [],
"server": {
"address": "localhost:7687",
"version": "Neo4j/3.2.0"
},
"resultConsumedAfter": {
"low": 37,
"high": 0
},
"resultAvailableAfter": {
"low": 3,
"high": 0
}
}
}
http://jsfiddle.net/9fR23/498/
please let me know how to fix this
ApprovalStatusShrtStrngVal FluidCodeShrtStrngVal (Header)
Working P (Values)
You have to loop through your array properly to get the desired result.
<table border="1">
<tr>
<th ng-repeat="(key, val) in collectioninfo.records[0]._fields[0].properties">{{ key }}</th>
</tr>
<tr ng-repeat="row in collectioninfo.records">
<td ng-repeat="column in row._fields[0].properties">
{{ column }}
</td>
</tr>
</table>
Working Fiddle :http://jsfiddle.net/9fR23/499/

ng-repeat in a table with colspan and rowspan

Here's a fiddle with the desired table and the Javascript function containing the array from where I want to populate the table, what I don't figure out is how, because if I use rowspan and colspan I have to create different <tr> for each product...
If there's another way to get the desired table I'd love to know about it... The main question here is: How could I use ng-repeat in a table that uses rowspan and colspan?
Also, the colspan and rowspan values at the <thead> can't be static as in the jsfiddle since each row may contain different amount of products... So the second question is: How could I dynamically set the rowspan value? they should be specified in each table row..
This is possible if you let the rowspan depend on inventory.length for the current transaction, and then you use nested ng-repeats.
Here we go:
var myApp = angular.module('myApp', []);
function MainCtrl($scope) {
var vm = $scope;
vm.hello = 123;
vm.transactions = [{
id: 1,
cost: 100,
transaction_type: { id: 1, name: 'Sell' },
client: { id: 2, name: 'XCLIENT' },
inventory: [
{ id: 1, quantity: 4, product: { id: 1, name: 'Cup' }, product_condition: { id: 2, name: 'New' } },
{ id: 2, quantity: 10, product: { id: 2, name: 'Shirt' }, product_condition: { id: 2, name: 'New' } }
]
}, {
id: 2,
cost: 40,
transaction_type: { id: 2, name: 'Buy' },
supplier: { id: 3, name: 'XSUPPLIER' },
inventory: [
{ id: 1, quantity: 2, product: { id: 1, name: 'Cup' }, product_condition: { id: 2, name: 'New' } },
{ id: 2, quantity: 5, product: { id: 6, name: 'Pants' }, product_condition: { id: 2, name: 'New' } }
]
}];
}
table,
th,
td {
border: 1px solid black;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app>
<table ng-controller="MainCtrl">
<thead>
<div>
<tr>
<td rowspan=2>Movement</td>
<td colspan=3>Products</td>
<td rowspan=2>Supplier</td>
<td rowspan=2>Cost</td>
</tr>
<tr>
<td>Name</td>
<td>Quantity</td>
<td>Condition</td>
</tr>
</div>
</thead>
<tbody ng-repeat="t in transactions">
<tr>
<td rowspan="{{t.inventory.length}}">Sell</td>
<td>{{t.inventory[0].product.name}}</td>
<td>{{t.inventory[0].quantity}}</td>
<td>{{t.inventory[0].product_condition.name}}</td>
<td rowspan="{{t.inventory.length}}">XCLIENT</td>
<td rowspan="{{t.inventory.length}}">$100</td>
</tr>
<tr ng-repeat="item in t.inventory" ng-if="$index > 0">
<td>{{item.product.name}}</td>
<td>{{item.quantity}}</td>
<td>{{item.product_condition.name}}</td>
</tr>
</tbody>
</table>
</div>
(Fiddle)
Here it is the totally dynamic way including dynamic rowspan :
HTML:
<div ng-app>
<h3>Here's what I want it to be</h3>
<div ng-controller="MainCtrl">
<table >
<thead>
<tr>
<td rowspan='{{rowspan}}'>Movement</td>
<td colspan='{{rowspan}}'>Products</td>
<td rowspan='{{rowspan}}'>Supplier</td>
<td rowspan='{{rowspan}}'>Cost</td>
</tr>
<tr>
<td>Name</td>
<td>Quantity</td>
<td>Condition</td>
</tr>
</thead>
<tbody ng-repeat='t in transactions'>
<tr ng-init='invCustom=(t.invetory.splice(1))'>
<td rowspan='{{rowspan}}'>{{t.transaction_type.name}}</td>
<td>{{t.invetory[0].product.name}}</td>
<td>{{t.invetory[0].quantity}}</td>
<td>{{t.invetory[0].product_condition.name}}</td>
<td ng-if='$index==0' rowspan='{{rowspan}}'>{{t.client.name}}</td>
<td ng-if='$index==1' rowspan='{{rowspan}}'>{{t.supplier.name}}</td>
<td rowspan='{{rowspan}}'>{{ t.cost | currency }}</td>
</tr>
<tr ng-repeat='tsub in invCustom'>
<td>{{tsub.product.name}}</td>
<td>{{tsub.quantity}}</td>
<td>{{tsub.product_condition.name}}</td>
</tr>
</tbody>
</table>
</div>
<h4>This data isn't loaded from the controller, I'd like to know how to use ng-repead in this case</h4>
</div>
JS:
function MainCtrl($scope) {
//var vm = this;
$scope.rowspan = 3;
$scope.transactions = [{
id: 1,
cost: 100,
transaction_type: {
id: 1,
name: 'Sell'
},
client: {
id: 2,
name: 'XCLIENT'
},
invetory: [{
id: 1,
quantity: 4,
product: {
id: 1,
name: 'Cup'
},
product_condition: {
id: 2,
name: 'New'
}
}, {
id: 2,
quantity: 10,
product: {
id: 2,
name: 'Shirt'
},
product_condition: {
id: 2,
name: 'New'
}
},
{
id: 3,
quantity: 101,
product: {
id: 3,
name: 'Shirt_C'
},
product_condition: {
id: 3,
name: 'New_C'
}
}]
}, {
id: 2,
cost: 40,
transaction_type: {
id: 2,
name: 'Buy'
},
supplier: {
id: 3,
name: 'XSUPPLIER'
},
invetory: [{
id: 1,
quantity: 2,
product: {
id: 1,
name: 'Cup'
},
product_condition: {
id: 2,
name: 'New'
}
}, {
id: 2,
quantity: 5,
product: {
id: 6,
name: 'Pants'
},
product_condition: {
id: 2,
name: 'New'
}
},
{
id: 3,
quantity: 55,
product: {
id: 7,
name: 'Pants_C'
},
product_condition: {
id: 8,
name: 'New_C'
}
}]
}];
}
try below code and do not forgot to include angular JS library....
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0-beta.2/angular.min.js
"></script>
<div ng-app>
<h3>Here's what I want it to be</h3>
<div ng-controller="MainCtrl">
<table >
<thead>
<tr>
<td rowspan=2>Movement</td>
<td colspan=3>Products</td>
<td rowspan=2>Supplier</td>
<td rowspan=2>Cost</td>
</tr>
<tr>
<td>Name</td>
<td>Quantity</td>
<td>Condition</td>
</tr>
</thead>
<tbody ng-repeat='t in transactions' ng-init='i=0'>
<tr>
<td rowspan=2>{{t.transaction_type.name}}</td>
<td>{{t.invetory[i].product.name}}</td>
<td>{{t.invetory[i].quantity}}</td>
<td>{{t.invetory[i].product_condition.name}}</td>
<td ng-if='$index==0' rowspan=2>{{t.client.name}}</td>
<td ng-if='$index==1' rowspan=2>{{t.supplier.name}}</td>
<td rowspan=2>{{ t.cost | currency }}</td>
</tr>
<tr>
<td>{{t.invetory[i+1].product.name}}</td>
<td>{{t.invetory[i+1].quantity}}</td>
<td>{{t.invetory[i+1].product_condition.name}}</td>
</tr>
</tbody>
</table>
</div>
<h4>This data isn't loaded from the controller, I'd like to know how to use ng-repead in this case</h4>
</div>
How could I use ng-repeat in a table that uses rowspan and colspan?
Yes you can use, I will put a very basic example and not fix the entire thing for you.
<table>
<tr ng-repeat="item in mylist">
<td ng-if="someCondition2" rowspan="2">AAA</td>
<td ng-if="someCondition1" colspan="2">BBB</td>
<td ng-if="someCondition3">CCC</td>
<tr>
</table>
This way you can conditionally add rowspan or colspan where ever required, hope you get the idea.

Resources