Item Array as Datasource for NgFor - arrays

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

Related

How to put distinct buttons in Angular mat-table?

I'm using angular mat table to display an array of data like below with simple sorting. The final column is a column of buttons. I'd like to have distinct buttons in each row that route to a different component.
Array as a table
<!-- Name Column -->
<ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Name </th>
<td mat-cell *matCellDef="let device"> {{device.name}} </td>
</ng-container>
<!-- SerialNo Column -->
<ng-container matColumnDef="serialNo">
<th mat-header-cell *matHeaderCellDef > SerialNo </th>
<td mat-cell *matCellDef="let device"> {{device.serialNo}} </td>
</ng-container>
<!-- Button Column -->
<ng-container matColumnDef="actions">
<th mat-header-cell *matHeaderCellDef > Actions </th>
<td mat-cell *matCellDef="let row" >
<button mat-button routerLinkActive="list-item-active" routerLink="/device1" >View</button>
</td>
my component.ts is like this.
export interface Devices {
name: string;
position: number;
serialNo: number;
}
//An Array of device1
const DEVICES: Devices[] = [
{position: 1, name: 'Device 1', serialNo: 135421},
{position: 2, name: 'Device 2', serialNo: 125240},
{position: 3, name: 'Device 3', serialNo: 124350},
{position: 4, name: 'Device 4', serialNo: 124500},
{position: 5, name: 'Device 5', serialNo: 145620},
];
displayedColumns: string[] = ['position', 'name', 'serialNo', 'actions'];
dataSource = new MatTableDataSource(DEVICES);
#ViewChild(MatSort) sort: MatSort;
ngAfterViewInit() {
this.dataSource.sort = this.sort;
}
How would I go about adding distinct buttons in each row that use routerLink to route to different components.
Do you want to redirect each link to a different angular component or do you want to redirect each link to the same angular component (for example, a device detail component), but with different url and device information (like redirecting to '/device/1', 'device/2' etc..)?
If the latter is the case, suppose you want to redirect each device to an angular route '/device-detail/:id', where id is the identification of the device. For simplicity, suppose id is the serialNo. So you just need to change the button declaration. Substitute routerLink="/device1" for [routerLink]="['/device-detail', device.serialNo]" (I also changed *matCellDef="let row" to *matCellDef="let device"):
<td mat-cell *matCellDef="let device" >
<button mat-button routerLinkActive="list-item-active" [routerLink]="['/device-detail', device.serialNo]" >View</button>
</td>

Angular 7 mat-table with array in array

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

How to create a table in Angular based on a string value?

I'm using Angular 4/5 and I have to create several tables in the Angular based on a string value. Here is the model which I've made to create a table.
class NameValuePair {
Name: string;
Value: string;
}
export class Family {
Properties: Array<NameValuePair>;
PropertyType: string;
}
Given below is the hard-coded values which the table will contain.
export const list1: Family[] =
[
{
Properties: [
{
Name: "A",
Value: "1"
},
{
Name: "B",
Value: "2"
},
{
Name: "C",
Value: "3"
}
],
PropertyType: "Type 1"
},
{
Properties: [
{
Name: "A",
Value: "10"
},
{
Name: "B",
Value: "20"
},
{
Name: "C",
Value: "30"
}
],
PropertyType: "Type 1"
},
{
Properties: [
{
Name: "A",
Value: "100"
},
{
Name: "B",
Value: "200"
},
{
Name: "C",
Value: "300"
}
],
PropertyType: "Type 2"
}
]
Now, the main thing to note here is that the tables will be created based on the PropertyType. As in the above structure, the PropertyType of the first two elements of the array is same i.e. Type 1 so 2 tables will be created. One with the caption/heading: Type 1 and other with the caption: Type 2.
The properties[] array of the second array element will become the second row of the first table. I'm not able to find the logic on how do I create the tables based on this PropertyType string value. However, that's what I wrote in the component.html file but this logic is incorrect.
<div class="container pt-4" *ngFor="let element of list;let i = index">
<ng-container *ngIf="list[i].PropertyType == list[i+1].PropertyType">
<div style="padding-left:250px;font-size: 20px" class="pb-2">{{element.PropertyType}}</div>
<table id="{{element.PropertyType}}" class="table table-striped table-bordered table-responsive pb-3 mx-auto">
<thead style="height:40px">
<tr align="center">
<th *ngFor="let property of element.Properties" style="font-size: 20px">{{property.Name}}</th>
</tr>
</thead>
<ng-container *ngFor="let element1 of list">
<tr align="center" *ngIf="element.PropertyType == element1.PropertyType">
<td *ngFor="let property of element1.Properties; let propertyIndex = index" style="width: 200px">
<ng-container [ngSwitch]="propertyIndex">
<div *ngSwitchDefault style="font-size: 20px">{{property.Value}}</div>
</ng-container>
</td>
</tr>
</ng-container>
</table>
</ng-container>
</div>
list here refers to the list1 const array as mentioned above. Please help.
This is complete logic, I did not add css, since that is not asked. Use this it is working https://stackblitz.com/edit/angular-hd9jey
import {
Component
} from '#angular/core';
import {
list1
} from './list1';
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
})
export class AppComponent {
tableArray = [];
constructor() {
let tableObject = {};
list1.forEach(i => {
if (tableObject[i.PropertyType]) {
tableObject[i.PropertyType].push(i);
} else {
tableObject[i.PropertyType] = [i];
}
this.tableArray = Object.entries(tableObject);
});
}
}
<div class="container pt-4" *ngFor="let table of tableArray;index as i">
<div style="padding-left:250px;font-size: 20px" class="pb-2">{{table[0]}}</div>
<table id="{{table[0]}}" class="table table-striped table-bordered table-responsive pb-3 mx-auto">
<thead style="height:40px">
<tr align="center">
<th *ngFor="let property of table[1][0].Properties" style="font-size: 20px">
{{property.Name}}</th>
</tr>
</thead>
<tr *ngFor="let property of table[1];" align="center">
<td *ngFor="let va of property.Properties">
{{va.Value}}
</td>
</tr>
</table>
</div>
You want to manipulate your list1 data into a nicer format first:
e.g.
export interface CustomTable {
header: string,
rows: Properties[]
}
const tables: CustomTable[] [];
list1.forEach(family => {
// Check if this type is already in the table.
const myTable: CustomTable = tables.find(customTable => customTable.header === family.propertyType);
if (myTable) {
// If it is, then add a new row
myTable.rows.push(family.Properties);
} else {
// If not, create a new table
myTable.rows.push({
header: family.propertyType,
rows: [family.Properties]
});
}
});
Then change your html accordingly. You probably want
<ng-container ngFor="let table of tables">
and within that somewhere a:
<tr *ngFor=let row of tables.rows>

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

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