I need to display below object of array in html table like that image. My data array like this.
data = [{id: 0 , name: 'one' , tags: ['a' , 'b' , 'c']} , {id: 1 , name: 'two', tags: ['r' , 't' , 'y']} , {id: 2 , name: 'three' , tags: ['a' , 'b' , 'c']} , {id: 3 , name: 'four' , tags: ['a' , 'b' , 'c']}]; .
So i tried like this but it's not working as expect on image.
<table class="table table-hover table-bordered">
<thead>
<tr>
<th scope="col">Tag Type</th>
<th scope="col">Tags</th>
<th scope="col">Action</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let tag of data; let i = index">
<td>{{ tag.id }}</td>
<table class="table">
<tr *ngFor="let el of tag.tags">
<td>{{el}}</td>
</tr>
</table>
<td>
<div align="center">
<a matTooltip="edit tag"><i>mode_edit</i></a>
</div>
</td>
</tr>
</tbody>
</table>
this is the result i got.Any idea how to do this?
I have made a few modifications into the code.
Instead of creating a new nested table,I have tried create separate rows in the main table. I have hid the TagType And Action, where it is not to be displayed based on the index.
For the striped pattern, I have added "table-striped" class to the table.
The Html code would look like this
<table class="table table-hover table-bordered table-striped">
<thead>
<tr>
<th scope="col">Tag Type</th>
<th scope="col">Tags</th>
<th scope="col">Action</th>
</tr>
</thead>
<tbody>
<ng-container *ngFor="let tag of data; let i = index">
<tr *ngFor="let el of tag.tags; let i2=index">
<td *ngIf="i2==0"> {{tag.id}} </td>
<td *ngIf="i2!=0"> </td>
<td> {{el}} </td>
<td>
<div align="center">
<a matTooltip="edit tag"><i>mode_edit</i></a>
</div>
</td>
</tr>
</ng-container>
</tbody>
</table>
StackBlitz working demo: https://stackblitz.com/edit/angular-ivy-aqmrzy
Related
Can I use an ngFor instead of repeating <table> two times?
NB: I thought to combine all the items into objects as items of a single array of mapping(each object contains a variable, label and value) but it does not work for me)
....
this.maxValueTable.push(selectedData.res.maxValue);
this.minValueTable.push(selectedData.res.minValue);
...
<div style="display: flex;">
<table style="width:100%;">
<thead>
<tr>
<th>Max</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let maxValue of maxValueTable">
<td> {{ maxValue | numberFormatter: (getUnit() | async)}}</td>
</tr>
</tbody>
</table>
<table style="width:100%;">
<thead>
<tr>
<th>Min</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let maxValue of minValueTable">
<td> {{ MinValue| numberFormatter: (getUnit() | async)}}</td>
</tr>
</tbody>
</table>
</div>
Another way:
<!--create an array directly in the .html: you can also use
a variable in your .ts-->
<table *ngFor="let table of [{head:'Max',data:maxValueTable},
{head:'Max',data:maxValueTable}]
style="width:100%;">
<thead>
<tr>
<!--use table.head-->
<th>{{table.head}}</th>
</tr>
</thead>
<tbody>
<!--see how iterate over table.data-->
<tr *ngFor="let maxValue of table.data">
<td> {{ maxValue | numberFormatter: (getUnit() | async)}}</td>
</tr>
</tbody>
</table>
If your arrays has the same length and only want a table, iterate over one array ans use the index to get the value of the another one
<table style="width:100%;">
<thead>
<tr>
<th>Max</th>
<th>Min</th>
</tr>
</thead>
<tbody>
<!--see the "let i=index"-->
<tr *ngFor="let maxValue of maxValueTable;let i=index">
<td> {{ maxValue | numberFormatter: (getUnit() | async)}}</td>
<!--use the "index" "i" to get the element of the another array-->
<td>
{{ minValueTable[i] | numberFormatter: (getUnit() | async)}}
</td>
</tr>
</tbody>
</table>
in this case you can also use map to create a new Array
minMax=this.minValueTable.map((x,index)=>({
min:x,
max:this.maxValueTable[index]
}))
And use {{value.min}} and {{value.max}}
You can create a function that will combine min and max values into an array like that:
mergeIntoArray(maxValue: Array<number>, minValue: Array<number>): IMergedObj[] {
let mergedArray = [];
maxValue.forEach((value, index) => {
let tempObj = {};
tempObj['maxValue'] = value;
tempObj['minValue'] = minValue[index];
mergedArray.push(tempObj);
});
return mergedArray;
}
and call this function like that:
let minAndMax = [];
this.minAndMax = this.mergeIntoArray(this.maxValueTable, this.minValueTable);
after that, use this variable (minAndMax) in your HTML template. This way you do not need to use ngFor twice.
<table style="width:100%;">
<thead>
<tr>
<th>Max</th>
<th>Min</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let item of minAndMax">
<td>{{ item.maxValue }}</td>
<td>{{ item.minValue }}</td>
</tr>
</tbody>
</table>
Here is the stackblitz link created for you. Hope that might help you.
You can use *ngTemplateOutlet for this case:
<div style="display: flex;">
<ng-container *ngTemplateOutlet="tableTemplate; context: {$implicit: maxValueTable, header: 'Max'}"></ng-container>
<ng-container *ngTemplateOutlet="tableTemplate; context: {$implicit: minValueTable, header: 'Min'}"></ng-container>
</div>
<ng-template #tableTemplate let-values, let-header="header">
<table style="width:100%;">
<thead>
<tr>
<th>{{ header }}</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let value of values">
<td> {{ value | numberFormatter: (getUnit() | async) }}</td>
</tr>
</tbody>
</table>
</ng-template>
And you will get the same table rendered twice - for Max and Min values.
As you can see, the arguments are passed as a second argument inside ngTemplateOutlet:
context: {$implicit: valuesArgument, header: headerArgument}
Later you could use this template to create infinite amount of tables:
<div *ngFor="let table of tables">
<ng-container *ngTemplateOutlet="tableTemplate; context: {$implicit: table.values, header: table.header}"></ng-container>
</div>
Assuming your tables property will look like
export class C {
tables: Table[] = [{header: 'Min', values: [1, 2, 3]}, {header: 'Max', values: [4, 5, 6]}, {header: 'Other', values: [0, -1, -2]}]
}
I have an array booksArr of objects of class book.
book.ts class
export class Book{
bookId:number;
bookName:string;
cost:number;
quantity:number;
constructor(bookId, bookType, cost, quantity){
this.cost=cost;
this.bookId=bookId;
this.bookName=bookName;
this.quantity=quantity;
}}
booksArr in books-list.component.ts
booksArr: book[] = [
new book(100, "The Alchemist", 20, 1),
new book(101, "Rich Dad Poor Dad", 50, 2),
new book(102, "Charolett's Web", 10, 1),
new book(103, "Harry Potter", 70, 4),
new book(104, "Gone Girl", 150, 3),
];
I want to create a table in html to display the details of these books.
books-list.component.html
<table border="1" *ngIf="bName">
<thead>
<tr>
<th>book ID</th>
<th>book Name</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let b of booksArr">
<td *ngIf="b.//WHAT SHOULD I PUT HERE"</td>
</tr>
</tbody>
</table>
You are already iterating through the booksArr.just need to use interpolation to display the data. Try like this
<table border="1" *ngIf="bName">
<thead>
<tr>
<th>book ID</th>
<th>book Name</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let b of booksArr">
<td>{{b.bookId}}</td>
<td>{{b.bookName}}</td>
</tr>
</tbody>
</table>
You are already iterating the array of books with *ngFor="let b of booksArr".
You want to now interpolate the values from each book in the array. When you are inside the array, you have access to the loop variable you declare in *ngFor. In this case the loop variable is b. You can now bind to the properties on b using curly brace interpolation. {{b.bookId}}.
<table border="1" *ngIf="bName">
<thead>
<tr>
<th>book ID</th>
<th>book Name</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let b of booksArr">
<td>{{b.bookId}}</td>
<td>{{b.bookName}}</td>
</tr>
</tbody>
</table>
Try:
<td> {{ b.bookId }} </td>
<td> {{ b.bookName }} </td>
No *ngIf is required in this case. Just try the following
<tbody>
<tr *ngFor="let b of booksArr">
<td>{{b.bookId}}</td>
<td>{{b.bookName}}</td>
</tr>
</tbody>
And in your .ts file you should either change
constructor(bookId, bookName, cost, quantity)
Or
this.bookName=bookType;
inside your constructor
How can I get v-for to display table data in the same form as the following html:
<tr>
<th scope="col">Name</th>
<th scope="col">Price</th>
<th scope="col">Product ID</th>
<th></th>
</tr>
Currently I am using the following vue v-for code(below) but it is adding the table header(th) one below another. I would like the table header to display side by side.
<tr v-for="(column, index) in schema" :key="index">
<th scope="col">{{column}}</th>
</tr>
You just need to place v-for on the element you want to repeat, not it's parent.
For loop should be put on <th></th>
<tr>
<th v-for="(column, index) in schema" :key="index">{{column}}</th>
</tr>
Here is the official vue doc for list rendering: https://v2.vuejs.org/v2/guide/list.html
bind grid header and data separately.
<template>
<table>
<thead>
<tr>
<th v-for="(header,index) in gridHeader" :key="index">
{{header.displayName}}
</th>
</tr>
</thead>
<tbody>
<tr v-for="(data, index) in gridData" :key="index" >
<td>
{{data.name}}
</td>
<td>{{data.age}}
</td>
<td>{{data.place}}
</td>
</tr>
</tbody>
</table>
</template>
<script lang="ts">
import Vue from 'vue';
export default class HelloWorld extends Vue {
private gridHeader: object[] = [
{name: 'Name', displayName: 'Name'},
{name: 'Age', displayName: 'Age'},
{name: 'Place', displayName: 'Place'}
];
private gridData: any =[{name:'Tony',age:'31',place:'India'},
{name:'Linju',age:'26',place:'India'},
{name:'Nysa',age:'12',place:'India'}];
};
</script>
<style scoped>
</style>
I am having trouble getting focus on my table and i am not sure how i should mark it up so it could get access via keyboard.
<table class="table table-bordered">
<thead>
<tr>
<th scope="col" class="sortable" width="10%" (click)="onHeaderClick('id')"
[ngClass]="{'active': sortBy == 'id', 'ascending': sortOrder == 'asc', 'descending': sortOrder == 'desc'}">
Id
</th>
<th scope="col" class="sortable" width="50%" (click)="onHeaderClick('name')"
[ngClass]="{'active': sortBy == 'name', 'ascending': sortOrder == 'asc', 'descending': sortOrder == 'desc'}">
Name
</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let student of studentList" (click)="selectedStudent(student)">
<td>
{{student.uId}}
</td>
<td>
<a (click)="profile(student)">{{student.fields.Name}}</a>
</td>
</tr>
</tbody>
</table>
You should use button elements inside the table header cells instead of trying to make the th elements themselves interactive.
Buttons are designed to be interacted with and come with all the affordences to help the user work with them.
I am using angular.js to make a table like this:
<table>
<tr ng-repeat="order in orders">
<td>
{{order.custName}} ...(several columns)
</td>
</tr>
</table>
I would like to add a 2nd row for each order, so the table looks something like this:
order1ID order1Name order1Amnt
order1Comment
order2ID order2Name order2Amnt
order2Comment
order3ID order3Name order3Amnt
order3Comment
but I don't know how!
I have created a working CodePen example of how to solve this.
Relevant HTML:
<section ng-app="app" ng-controller="MainCtrl">
<table class="table table-bordered">
<thead>
<tr>
<th>Order ID</th>
<th>Order Name</th>
<th>Order Amount</th>
</tr>
</thead>
<tbody ng-repeat="order in orders">
<tr>
<td>{{order.id}}</td>
<td>{{order.name}}</td>
<td>{{order.amount}}</td>
</tr>
<tr>
<td colspan="3">
{{order.comment}}
</td>
</tr>
</tbody>
</table>
</section>
Relevant javascript:
var app = angular.module('app', []);
app.controller('MainCtrl', function($scope) {
$scope.orders = [{
id: '001',
name: 'Order 1 Name',
amount: 100.00,
comment: 'Order 1 comment goes here'
},{
id: '002',
name: 'Order 2 Name',
amount: 150.00,
comment: 'Order 2 comment goes here'
}];
});
Using Angular 1.2:
<table>
<tr ng-repeat-start="x in stuff">
<td>{{x.name}}</td>
</tr>
<tr ng-repeat-end="">
<td>{{x.value}}</td>
</tr>
</table>