Using ngif else to display a different value in table - html

I am getting data from the database. So in a particular column named card there exists only two types of values. "Debit" or "Credit". But in the backend I only receive values as "D" or "C".
`<div *ngIf="isBank">
<div class="table-responsive">
<table class="table">
<thead class="table_header">
<tr>
<th>Name</th>
<th>Bill</th>
<th>Card</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let bank of bankList; index as i">
<td>{{ bank.name}}</td>
<td>{{ bank.bill}}</td>
<td>{{ bank.card}}</td>
</tr>
</tbody>
</table>`
</div>
</div>
So here in the Card column I get only two values called as 'D' or 'C'. I get these values from the backend. So I want to change the value to 'Debit' if I get 'D' and 'Credit' if I get 'C'. This hads to be done within the template using ngif or whatever works.

You can define an angular pipe
card-type.pipe.ts:
import { Pipe, PipeTransform } from '#angular/core';
#Pipe({name: 'cardType'})
export class CardTypePipe implements PipeTransform {
transform(value: string): string {
if (value.toLowerCase() === "c")
return "Credit";
else if (value.toLowerCase() === "d")
return "Debit";
else
return value;
}
}
And in the template:
<tr *ngFor="let bank of bankList; index as i">
<td>{{ bank.name }}</td>
<td>{{ bank.bill }}</td>
<td>{{ bank.card | cardType }}</td>
</tr>
app.module.ts:
import { CardTypePipe } from './card-type.pipe';
#NgModule({
declarations: [
CardTypePipe
],
imports: [..],
providers: [..],
bootstrap: [AppComponent]
})
export class AppModule { }
If you think this pipe is an overkill, you can always use (I personally like my templates to be plain and simple):
<td>{{ bank.card === "D" | "Debit" : "Credit" }}</td>

Related

subscribe display [Object Object], can't make an *ngIf outside of *ngFor

I created an angular Quiz project, every ID can make quizzes and I want to display every Quiz that a logged user has done. I did it like this.
// here I call the user id and the id_category inside Result[], but I can't use it on the html part.
ngOnInit() {
this.supabase.authChanges((_, session) => this.session2 = session);
this.getProfile();
this.supabaseQuiz.getResult().subscribe((res: Result[]) => {
let resultIdAns = res
this.result = resultIdAns
//here I get the result = [Object, Object]
})
//passare category id
this.supabase.profile.then(profile => {
if(profile.data){
this.userProfile = profile.data
}else{
// this.router.navigateByUrl('account/addProfile')
}
})
}
this is the html part:
here I try to if the result.id_category with the userID to display only his quiz but this if inside the for destroy all the table!
<nz-table #headerTable [nzData]="result" [nzPageSize]="50" [nzScroll]="{ y: '240px' }">
<thead>
<tr>
<th>Category</th>
<th>Date</th>
<th>Correct answers</th>
<th>Final score</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let res of result">
<div *ngIf="this.userProfile?.id === res.id_profile">
<td>{{ res.categoryTitle }}</td>
<td>{{ res.date }}</td>
<td>{{ res.rightAnswer }}</td>
<td>{{ res.finalScore }}</td>
<button nz-button nzType="primary" success (click)="goToDetail(parameterValue)">Dettagli</button>
<!--<td>{{ res.json_answer }}</td>-->
</div>
</tr>
</tbody>
</nz-table>
there is way to do another subscribe maybe and get the result id_category outside the for? Thanks
1- You can make the filtering of the ids check in the ts file using array.find() against res.id_profile and userProfile?.id.
2- You do not need to create a new property named resultIdAns since you can assign the API endpoint response to the result property directly.
3- You cannot make the *ngIf="" check outside the *ngFor="" because the condition predicate in the *ngIf="" depends on the variable named res from the outer element which is the container of *ngFor=""
4- Your usage of this. keyword in the template inside the *ngIf="" is invalid.
5- whenever you want to use structural directive it is better for performance reasons to use <ng-container *ngIf="" ></ng-container> or <ng-container *ngFor="" ></ng-container>

how do I access nested json data with vuejs>

I would like to create a table and populate it with data using vue.js and v-for but I don`t know how to access the nested JSON file.
If I simply call {{items}} the data is presented but there is no way i manage to filter it
here is my code:
<template>
<div id="app">
<thead>
</thead>
<tbody>
<table>
<thead>
<tr>
<th>id</th>
<th>press</th>
<th>date</th>
</tr>
</thead>
<tbody>
<tr v-for="item in items" :key="item.id">
<td>{{ item.id }}</td>
<td>{{ item.results.downloadable.document_en }}</td>
<td>{{ item.}}</td>
</tr>
</tbody>
</table>
</tbody>
</div>
</template>
<script>
import axios from 'axios';
export default {
data() {
return {
items:[]
}
},
created() {
axios.get(`https://zbeta2.mykuwaitnet.net/backend/en/api/v2/media-center/press-release/?page_size=61&type=5`)
.then(response => {
this.items = response.data
})
}
}
</script>
Based on the result of your endpoint you should change your assignment of items to
.then(response => {
this.items = response.data.results
})
And your loop to
<tr v-for="item in items" :key="item.id">
<td>{{ item.id }}</td>
<!-- as downloadable is an array, see update below etc. -->
</tr>
But be aware - if you assign the data.results directly you will lose the so called "paginator" information that also contains the link to load more.
So another option would be to assign
this.items = response.data
HOWEVER, be aware that you should then define items in your data as null or empty object (not array, as this would be false)
And then change your loop to something like this (it's now looping in item.results)
<tbody v-if="items && items.results">
<tr v-for="item in items.results" :key="item.id">
<td>{{ item.id }}</td>
<!-- as downloadable is an array - see Update below etc. -->
</tr>
</tbody>
This approach would allow you to show the total count via items.count for example
UPDATE:
Actually downloadable is an array! I can only assume what you actually want to achieve to here. I've created a jsfiddle to showcase it: https://jsfiddle.net/v73xe4m5/1/
The main thing you probably want to do is filter the entry to only show entries where downloadable contains a document_en.
<tr v-for="item in items.results" :key="item.id">
<td>{{ item.id }}</td>
<td>
<div class="downloads">
<span
v-for="downloadable in item.downloadable.filter(d => !!d.document_en)"
:key="downloadable.id"
>{{ downloadable.document_en.file }}</span>
</div>
</td>
</tr>
I'm not familiar with that endpoint / api - so I don't know if it might return more than one relevant document per item.
As you can see I used a second v-for loop inside the <td> in order to go through all downloadable entries. Before doing so, they are filtered, so only entries that actually have a document_en value are shown. You can adapt this as you want.
Hope that helps!
this is the correct form to get the array from the json and save to this.items
this.items = response.data.results
I encourage you to always console.log(response) after api call , and access data according to the structure of the api results

Angular populating table with object data that has missing fields

i'm currently working on displaying large amounts of data in tables for a scientific project. i have timeStamps of experiments, which look like this:
interface TimeData {
time: string;
data: {SD: string, SEM: string, N: string, MEAN: string};
}
i have a total of 11 timeStamps in the table, all described by their 'time', e.g. 15, 30, 60, 90...
if an experiment is missing a timestamp completely or has no data for the timestamp 30 at e.g. MEAN, i want to print -- in the td.
i can't seem to wrap my head around how to display all mean data in a row and just replacing missing one's with a '--'...
i've tried wrapping in ng-container, several ngFor loops, yet it always comes out wrong, i.e. i get too many -- or none at all and my data is being displayed in the wrong td.
here's the html
<table class="table table-bordered">
<thead>
<tr>
<th scope="col">Code</th>
<th scope="col">Function</th>
<th scope="col" class="text-center"
*ngFor="let timeStamp of maxTimeStamps; let i=index">t{{i + 1}}
{{timeStamp.time}}</th>
<th>ΔAUC</th>
</tr>
</thead>
<tbody *ngFor="let experiment of report.experiments; let i = index">
<tr>
<td rowspan="4" [ngStyle]="{color: experimentColors[i]}">{{experiment.code.toUpperCase()}}</td>
<td>mean</td>
------missing td goes here-------
----------------------------------
</tr>
</tbody>
</table>
Welcome to StackOverflow, If I get it right you want to show your data in rows but you add ngFor in the wrong place for that (it shouldn't add to tbody tag)! please check the corrected code below.
You can change or make a condition by ngIf if you don't want to add that td.
Good Luck.
<table class="table table-bordered">
<thead>
<tr>
<th scope="col">Code</th>
<th scope="col">Function</th>
<th scope="col" class="text-center"
*ngFor="let timeStamp of maxTimeStamps; let i=index">t{{i + 1}}
{{timeStamp.time}}</th>
<th>ΔAUC</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let experiment of report.experiments; let i = index">
<td rowspan="4" [ngStyle]="{color: experiment.Colors[i]}" [ngIf]="experiment.CheckableItem == true">{{experiment.code.toUpperCase()}}</td>
<td>mean</td>
</tr>
</tbody>
</table>
If some of the properties will not be available in the interface then they should be defined optional. Notice the question mark.
interface TimeData {
time?: string;
data?: {SD?: string, SEM?: string, N?: string, MEAN?: string};
}
In the template, you could use *ngIf directive with an else clause to show '--' if some properties are not available. Try the following
Controller
import { Component, VERSION, ElementRef } from '#angular/core';
import { Router } from '#angular/router';
interface TimeData {
time?: string;
data?: {SD?: string, SEM?: string, N?: string, MEAN?: string};
}
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
timeData: TimeData[] = [
{time: '15', data: {SD: '10', SEM: '20', N: '30', MEAN: '75'}},
{data: {SD: '10', SEM: '20', N: '30', MEAN: '75'}},
{time: '15', data: {SD: '10', SEM: '20', N: '30'}},
{data: {SEM: '20', N: '30', MEAN: '75'}},
];
constructor(private _router: Router, private _el: ElementRef) { }
}
Template
<table>
<tr>
<th>Time</th>
<th>SD</th>
<th>SEM</th>
<th>N</th>
<th>MEAN</th>
</tr>
<tr *ngFor="let data of timeData">
<ng-container *ngIf="data.time; else emptyData">
<td>{{ data.time }}</td>
</ng-container>
<ng-container *ngIf="data.data.SD; else emptyData">
<td>{{ data.data.SD }}</td>
</ng-container>
<ng-container *ngIf="data.data.SEM; else emptyData">
<td>{{ data.data.SEM }}</td>
</ng-container>
<ng-container *ngIf="data.data.N; else emptyData">
<td>{{ data.data.N }}</td>
</ng-container>
<ng-container *ngIf="data.data.MEAN; else emptyData">
<td>{{ data.data.MEAN }}</td>
</ng-container>
<ng-template #emptyData>
<td>--</td>
</ng-template>
</tr>
</table>
Working example: Stackblitz

Exporting Table Contents from Angular to Excel Invokes Error When Attempting To Open Downloaded File

I am making a general application to make a table in Angular and then export that table to excel using the xlsx library and StackBlitz for development. No errors are thrown in the code itself but when I try to open the downloaded file, excel basically tells me that the file extension is invalid.
The error I am encountering
What I've done to debug the issue
Given the nature of the error I've mostly looked for typos in my code such as xslx vs xlsx etc. but to no avail it doesn't seem as if that's the problem. I have tried downloading the table as a CSV which seems to download ok except the table headers are not included (something I am also trying to fix) in the CSV file, but I can then successfully change the file extension from .csv to .xlsx with no problems.
app.component.ts
import { Component, ElementRef, ViewChild } from '#angular/core';
import * as xlsx from 'xlsx';
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
#ViewChild('TABLE', { static: false }) TABLE: ElementRef;
title = 'Excel';
constructor() {
console.log('e')
}
xport() {
const workSheet: xlsx.WorkSheet = xlsx.utils.table_to_sheet(this.TABLE.nativeElement)
const workBook: xlsx.WorkBook = xlsx.utils.book_new()
xlsx.utils.book_append_sheet(workBook, workSheet, 'Sheet 1');
xlsx.writeFile(workBook, 'itemSheet.xlsx')
}
header: any = [{
itemNumber: 'Item Number',
itemDescription: 'Item Description',
manufacturer: 'Manufacturer',
manufacturerPartNumber: 'Manufacturer Part Number'
}];
item: any = [{
itemNumber: 1,
itemDescription: 'An Item',
manufacturer: 'Manufacturer A',
manufacturerPartNumber: 123
},{
itemNumber: 2,
itemDescription: 'Another Item',
manufacturer: 'Manufacturer B',
manufacturerPartNumber: 124
},{
itemNumber: 3,
itemDescription: 'Yet Another Item',
manufacturer: 'Manufacturer C',
manufacturerPartNumber: 125
}]
}
app.component.html
<div #TABLE #table>
<div class="row">
<div class="col-sm-12">
<table style="width: 100%" class="table table-bordered">
<thead class = 'thead-dark' *ngFor="let h of header">
<th> {{ h.itemNumber }} </th>
<th> {{ h.manufacturer }} </th>
<th>{{ h.manufacturerPartNumber }}</th>
<th>{{ h.itemDescription }}</th>
</thead>
<tbody>
<tr *ngFor="let i of item">
<td> {{ i.itemNumber }}</td>
<td> {{ i.manufacturer }}</td>
<td> {{ i.manufacturerPartNumber }}</td>
<td> {{ i.itemDescription }}</td>
</tr>
</tbody>
</table>
</div>
<div>
<button (click)="xport()">Export to Excel</button>
</div>
</div>
</div>

Angular: Reset index value in the same template

I have a template of 3 tables having same JSON as parent like this.
<tbody>
<ng-container *ngFor="let row of reportingData.RecommendationData; let i=index">
<tr *ngIf="row.swRecommendations">
<td>{{i+1}}</td>
<td> {{row.swRecommendations.deviceID}}</td>
</tr>
</ng-container>
</tbody>
Another table body
<tbody>
<ng-container *ngFor="let row of reportingData.RecommendationData; let j=index">
<tr *ngIf="row.licenseRecommendations">
<td>{{j+1}}</td>
<td> {{row.licenseRecommendations.deviceID}}</td>
</tr>
</ng-container>
</tbody>
All these tables are in the same template. I'm assigning index values to different variables(i & j) but increment is happening i.e. if first table is having 5 rows, second table is starting with 6 not 1. How to fix this?
I tested you'r code and indexes are starting from 0 .
Please review my code.
Component.html
<h1>First Table</h1>
<table>
<tr>
<th>Id</th>
<th>Name</th>
</tr>
<ng-container>
<tr *ngFor="let a of array;let i = index">
<th>{{i + 1}}</th>
<th>{{a.name}}</th>
</tr>
</ng-container>
</table>
<h1>Second Table</h1>
<table>
<tr>
<th>Id</th>
<th>Name</th>
</tr>
<ng-container>
<tr *ngFor="let a of array;let j = index">
<th>{{j + 1}}</th>
<th>{{a.name}}</th>
</tr>
</ng-container>
</table>
Component.ts
import { Component } from '#angular/core';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styles: ['./app.component.scss']
})
export class AppComponent {
constructor() {}
public array = [
{ id: 1, name: 'aaa'},
{ id: 2, name: 'bbb'},
{ id: 3, name: 'ccc'},
{ id: 4, name: 'ddd'},
{ id: 5, name: 'eee'},
{ id: 6, name: 'fff'},
]
}
H recently faced the same issue, since we are indexing it and increment it will be like that, the solution of this problem is like this Filter your data in the ts
this.a= this.reportingData.filter(x => x.swRecommendations);
this.b= this.reportingData.filter(x => x.licenseRecommendations);
<tr *ngFor="let row of a"> <tr *ngFor="let row of b">,
and then remove the if condition and iterate the data in HTML like this let row of reportingData , editing needed based on your consition in ts