I have a source of data from a service like the following.
this.ateco2007 = [{code: this.anagrafica?.ateco2007?.code, description: this.anagrafica?.ateco2007?.description}]
if(this.anagrafica?.atecoSecondari && this.anagrafica?.atecoSecondari.length > 0) {
let i = 0;
for(let elem of this.anagrafica.atecoSecondari) {
this.atecoSecondari.push({
index: i++,
code: elem.code,
description: elem.description
});
}
...where ateco2007 has got always one elem, instead atecoSecondari can have multiple values. But there is always a pair code/description.
I want to show this data in a table. The first row will always be one row(ateco 2007), the other rows can be multiple.
I want a structure like this:
The first column will be always fix with the label, the second column shows the code and the last the description.
I tried the following, this is almost correct:
But I want to achieve something closer to the following:
As you see, there is a sort of rowspan and in the second and third columns, the rows have borders and are in the same line.
I tried the following code:
<p-table [value]="ateco2007" [autoLayout]="true">
<ng-template pTemplate="body">
<tr>
<td class="font-weight-bold"> {{'cliente.ateco'|translate}}</td>
<td>{{ateco2007[0]?.code}}</td>
<td class="text-left">{{ateco2007[0]?.description}}</td>
</tr>
<tr>
<td rowspan="atecoSecondari.length" class="font-weight-bold">
{{'cliente.atecoSecondari'|translate}}</td>
<td>
<table>
<tr *ngFor="let elem of atecoSecondari">
<td>{{elem.code}}</td>
</tr>
</table>
</td>
<td>
<table>
<tr *ngFor="let elem of atecoSecondari">
<td class="text-left">{{elem.description}}</td>
</tr>
</table>
</td>
</tr>
</ng-template>
But I don't know if it's the best way to build the table.
I solved it in this way
<p-table [value]="ateco2007" [autoLayout]="true">
<ng-template pTemplate="body" let-rowIndex="rowIndex">
<tr>
<td class="font-weight-bold"> {{'cliente.ateco'|translate}}</td>
<td>{{ateco2007[0]?.code}}</td>
<td class="text-left">{{ateco2007[0]?.description}}</td>
</tr>
<tr *ngFor="let elem of atecoSecondari">
<td *ngIf="rowIndex == elem.index" [attr.rowspan]="atecoSecondari.length" class="font-weight-bold">
{{'cliente.atecoSecondari'|translate}}
</td>
<td>{{elem.code}}</td>
<td class="text-left">{{elem.description}}</td>
</tr>
</ng-template>
</p-table>
I added the rowspan and changed the structure.
Related
I have a table that is displaying five rows of N/A when I would like to display just one row.
(HTML)
<ng-container *ngFor="let item of file?.fileConfigurations">
<tr *ngIf="item.file === element.file; else notapplicable">
<td> {{item.filename}} </td>
<td> {{item.day}} </td>
<td> {{item.week}} </td>
<td> {{item.time}} </td>
</tr>
</ng-container>
<ng-template #notapplicable>
<tr>
<td>N/A</td>
<td>N/A</td>
<td>N/A</td>
<td>N/A</td>
</tr>
</ng-template>
How can I just display one row of N/A if the ngIf condition is never met? Basically, it displays N/A repeatedly, for five times, when my ngIf condition is not met. This is because the ngFor loop loops through five file configurations.
I have tried removing ng-template, but then it never displays my N/A placeholder value in the data cell (which I want).
Assuming you have element is available in your ts file, you can pre-check for all file in fileConfigurations matches element.file
in component.ts
file: {fileConfigurations: any[]} = {
fileConfigurations: []
}
element = {
file: 'some data'
}
noFileExists() {
return this.file?.fileConfigurations.every(item => item.file !== this.element.file)
}
if the above condition matches, show single <tr>
in component.html
<ng-container *ngIf="noFileExists(); else fileLoop">
<tr>
<td>NA</td>
<td>NA</td>
<td>NA</td>
<td>NA</td>
</tr>
</ng-container>
<ng-template #fileLoop>
<ng-container *ngFor="let item of file?.fileConfigurations">
<tr *ngIf="item.file === element.file; else notapplicable">
<td> {{item.filename}} </td>
<td> {{item.day}} </td>
<td> {{item.week}} </td>
<td> {{item.time}} </td>
</tr>
</ng-container>
<ng-template #notapplicable>
<tr>
<td>N/A</td>
<td>N/A</td>
<td>N/A</td>
<td>N/A</td>
</tr>
</ng-template>
</ng-template>
You can create a parent element around the container,
And check if the childElementCount property is equal to 0.
<div #items>
<ng-container *ngFor="let item of file?.fileConfigurations">
<tr *ngIf="item.file === element.file">
<td> {{item.filename}} </td>
<td> {{item.day}} </td>
<td> {{item.week}} </td>
<td> {{item.time}} </td>
</tr>
</ng-container>
</div>
<tr [hidden]="items.childElementCount !== 0">
<td>N/A</td>
<td>N/A</td>
<td>N/A</td>
<td>N/A</td>
</tr>
Number of persons and their mobiles numbers are dynamic. I need to show this in table.
Data can contain any number of pname and mobile numbers.
dataList = [
{
pname: "abc",
numbers: [{mobile1: 123, mobile2: 234}]
},
{
pname: "mno",
numbers: [{mobile1: 125, mobile2: 237}]
}
]
Template
<tr *ngFor="let data of dataList">
<td [attr.rowspan]="data.numbers.lenght">data.pname</td>
<td>data.numbers</td> // Here how do I show all mobile numbers of the person.
</tr>
Expected output is of below code.
table, th, td {
border: 1px solid black;
}
<table>
<tr>
<th>Pname</th>
<th>Numbers</th>
</tr>
<tr>
<td rowspan="2">Abc</td>
<td>123</td>
</tr>
<tr>
<td>234</td>
</tr>
<tr>
<td rowspan="2">Mno</td>
<td>125</td>
</tr>
<tr>
<td>237</td>
</tr>
</table>
Problem I am facing is I need to add tr after each run of *ngFor and the number of tr will depend on length of numbers array to make row span.
You can do it like shown below
<table>
<ng-container *ngFor="let data of dataList">
<tr>
<td [attr.rowspan]="data.numbers.length">{{data.pname}}</td>
<td>{{data.numbers[0]}}</td>
</tr>
<ng-container *ngFor="let number of data.numbers; let i= index;">
<tr *ngIf="i!=0">
<td>{{number}}</td>
</tr>
</ng-container>
</ng-container>
</table>
But datalist must be of the following format i.e. numbers must be an array
dataList = [
{
pname: "abc",
numbers: [123, 234]
},
{
pname: "mno",
numbers: [125, 237]
}
]
Simple.
You don't need index and nested ng-container.
<table>
<ng-container *ngFor="let data of dataList">
<tr>
<td [attr.rowspan]="data.numbers.length + 1">{{data.pname}}</td>
</tr>
<tr *ngFor="let number of data.numbers;">
<td>{{number}}</td>
</tr>
</ng-container>
</table>
Working example.
https://stackblitz.com/edit/angular-yrose8?file=src%2Fapp%2Fapp.component.html
it is simple to use two *ngFor and avoid repeat Code by data.numbers[0].
<table>
<ng-container *ngFor="let data of dataList">
<ng-container *ngFor="let number of data.numbers; let i= index;">
<tr>
<td *ngIf="i==0" [attr.rowspan]="data.numbers.length">{{data.pname}}</td>
<td>{{number}}</td>
</tr>
</ng-container>
</ng-container>
</table>
What would be the best way to dynamically add an HTML element, such as another column onto a basic HTML table?
I want to have a button below the table, and if the user were to click the button, the event would add the same amount of rows already in the table and add another column. I would want to support about 5 extra columns being added to the table.
Here's my HTML table as of right now:
<table>
<thead>
<tr>
<th id="row-tag"></th>
<th id="option-column">Option 1</th>
</tr>
</thead>
<tbody>
<tr>
<td id="row-tag">P</td>
<td id="option-column">{{ p }}</td>
</tr>
<tr id="row-tag">
<td>
<app-a-p (saveButtonClick)="toggleAP($event)"
[modModalValues]="modModalValues">
</app-a-p>
</td>
<td id="option-column">
<div class="input-group input-group-sm">
$<input
*ngIf="toggleAP==true"
type="text"
name="aP"
size="10"
disabled
value=""
/>
<input
*ngIf="toggleAP==false"
type="text"
name="aP"
size="10"
[ngModel]="con.pA"
(ngModelChange)="con.pA = $event" appFormatP
(blur)="checkAP($event.target.value);
inputTracker.addModifiedValue('Option 1', $event.target.value)"
/>
</div>
</td>
</tr>
<tr>
<td id="row-tag">L</td>
<td id="option-column">${{l}}</td>
</tr>
<tr>
<td id="row-tag">R</td>
<td id="option-column">${{r}}</td>
</tr>
</tbody>
</table>
I think in Angular, you define table based on your data. for example, you have fields array defining columns, and data array defines the what's actually in the table.
<table >
<thead>
<tr>
<th *ngFor='let key of this.fields'>{{key}}</th>
</tr>
</thead>
<tbody>
<tr *ngFor='let row of this.data ' >
<td scope="row" *ngFor='let key of this.fields'> {{row[key]}} </td>
</tr>
</tbody>
</table>
when you need a new column, just push a new field into fields. like
fields.push('newcolumn');
when you need a new row, just do:
data.push({col1: '', col2:'', newcolumn: ''});
Look into the insertRow() and insertCell() functions in JavaScript. This alongside an onClick function that you write will let you edit the table.
A good way of generating a table on UI when using angular would be to use 2D-array (row*column) use can have a button using which you can dynamically add values to this array and have another row/column to the table.
I am displaying table data using NgTableParams in angularjs. I was trying to show NO DATA EXISTS in the table when the data is not available or length is zero, but my code doesn't seems to work.
Demo : http://plnkr.co/edit/nEbjQE1NQW7VF8dlZvyy?p=preview
sample code:
<table ng-table="tableParams" class="table" show-filter="true">
<tbody ng-repeat="user in $data">
<tr ng-show="$data.length > 0">
<td title="'Name'" filter="{ name: 'text'}" sortable="'name'">
{{user.name}}</td>
<td title="'Age'" filter="{ age: 'number'}" sortable="'age'">
{{user.age}}</td>
</tr>
<tr ng-show="$data.length === 0">
<td title="'Name'" filter="{ name: 'text'}" sortable="'name'">
NO DATA FOUND</td>
<td title="'Age'" filter="{ age: 'number'}" sortable="'age'">
</td>
</tr>
</tbody>
js code:
app.controller('MainCtrl', function($scope, NgTableParams) {
$scope.data1 = [];
console.log(" $scope.data1 length " + $scope.data1.length);
$scope.tableParams = new NgTableParams({}, { dataset: $scope.data1});
});
Tried as below too , but it is not displaying the table header and filter for the columns..
Demo : http://plnkr.co/edit/XAOO5tPALVOkQW9hhJCs?p=preview:
<tbody ng-show="!$data.length">
<tr>
<td>
NO DATA FOUND
</td>
</tr>
</tbody>
<tbody ng-repeat="user in $data">
<tr ng-show="$data.length > 0">
....
</tbody>
There are two issues here
The first one is that your ng-repeat directive is in your tbody this will cause your table body to be rendered for every single element in your array.
The second one is that your "NO DATA FOUND" message is inside of your ng-repeat block, no element will be rendered if $data is empty.
The solution would be to move the ng-repeat from your tbody to the actual element that you want to repeat for every item in your array, in this case, the tr that contains the data to be displayed.
<table ng-table="tableParams" class="table" show-filter="true">
<tbody>
<tr ng-repeat="user in $data" ng-show="$data.length > 0">
<td title="'Name'" filter="{ name: 'text'}" sortable="'name'">
{{user.name}}</td>
<td title="'Age'" filter="{ age: 'number'}" sortable="'age'">
{{user.age}}</td>
</tr>
<tr ng-show="$data.length === 0">
<td title="'Name'" filter="{ name: 'text'}" sortable="'name'">
NO DATA FOUND</td>
<td title="'Age'" filter="{ age: 'number'}" sortable="'age'"></td>
</tr>
</tbody>
</table>
Hope it helps!
Seems to be the same requirement like AngularJS "Vertical" ng-repeat but solution doesn't work for *ngFor
I have this object array that I am trying to bind to an HTML table. Its format is something like below:
[
{
"Animal":"Dog",
"Country":"France",
"Food":"Tofu",
"Car":"Nano",
"Language":"TypeScript"
}
]
Now this can simply be formatted in the default HTML horizontal table way like this:
<table>
<tr>
<th>Animal</th>
<th>Country</th>
<th>Food</th>
<th>Car</th>
<th>Language</th>
</tr>
<tr *ngFor="let data of datas">
<td>{{data.Animal}}</td>
<td>{{data.Country}}</td>
<td>{{data.Food}}</td>
<td>{{data.Car}}</td>
<td>{{data.Language}}</td>
</tr>
</table>
This would create table like below(Please ignore the data in the table;its just to give an idea.):
But how would I create a structure like this with dynamic data(kind of a vertical table):
In Component:
this.arrayOfKeys = Object.keys(this.datas[0]);
html:
<table>
<tr *ngFor="let key of arrayOfKeys">
<th>{{key}}</th>
<td *ngFor="let data of datas">
{{data[key]}}
</td>
</tr>
</table>
Use ng-container if You have data structure similar to groups[].items[].name
So, if You want to add row
<table>
<ng-container *ngFor="let group of groups">
<tr>
<td>{{group.name}}</td>
</tr>
<tr *ngFor="let item of group.items">
<td>{{item.name}}</td>
</tr>
</ng-container>
</table>
Source: https://stackoverflow.com/a/44086855/1840185