I am wondering how I can only show specific values with the key-value pipe. So far I have tried to do item.value.form_name but that comes up as null when the property is set from my API. When I do item.value then it shows me all of the items in the object. I only want the form name and the organization to show.
Code:
<div class="form-details">
<div *ngFor="let item of form?.results | keyvalue">
<span class="col-6">{{item.value.id}}</span>
<span class="col-6">{{item.value.org}}</span>
</div>
</div>
How the data is being received
Try like this:
Working Demo
<div *ngFor="let item of form?.results | keyvalue">
<ng-container *ngIf="item.key == 'id' || item.key == 'org'">
<span class="col-6">{{item.value}}</span>
</ng-container>
</div>
you can try this
<div class="form-details">
<div *ngFor="let item of form?.results | keyvalue">
<span class="col-6">{{item.value.id == 'null' ? '' : item.value.id}}</span>
<span class="col-6">{{item.value.org == 'null'? '' : item.value.org}}</span>
</div>
</div>
<div class="form-details">
<div *ngFor="let item of results | keyvalue">
<div *ngIf="item.key == 'id' || item.key == 'org'">
<span class="col-6">{{item.value}}</span>
</div>
</div>
</div>
Try this, you can minimize the code with some thing like this.
<div *ngFor="let item of form?.results | keyvalue">
<ng-container *ngIf="item.key == ('id' || 'org')">
<span class="col-6">{{item.value}}</span>
</ng-container>
</div>
Related
Need to slice the inner ngfor loop into 3 parts
<div class="row" *ngFor="let row of matrix; index as i">
<div class="col" *ngFor="let col of row; index as j">
<div *ngFor="let placeholder of placeholders | slice:i:j">
<ng-container [ngComponentOutlet]="placeholder.component" >
</ng-container>
</div>
</div>
</div>
There are a couple of ways around this:
$any
<p *ngFor="let item of data | slice:2:4">
{{ $any(item).parentName }}
</p>
Bracket notation
<p *ngFor="let item of data | slice:2:4">
{{ item['parentName'] }}
</p>
A function
slicedData(data : any[]) : any[] {
return data.slice(2,4)
}
<p *ngFor="let item of slicedData(data)">
{{ item['parentName'] }}
</p>
I have a json object that has an inner object called data, which has data: {count: 9, message: "9 sites synced"} - also json object. I'm trying to get the value from message, not from count. Here is my template code:
<div class="full-width border-radius-4 overflow-hidden">
<!-- Header -->
<div class="head accent p-24 pb-16" fxLayout="column" fxLayoutAlign="space-between">
<div fxLayout="row" fxLayoutAlign="end center">
</div>
</div>
<mat-accordion class="full-width example-headers-align" multi *ngIf="liveActions$ | async as actions; else: loading">
<mat-expansion-panel *ngFor="let action of actions">
<mat-expansion-panel-header *ngIf="action.type == 'single'">
<mat-panel-description fxFlex="30%">
<div class="lgreen material-icons" *ngIf="action.status == 'completed'">done_all</div>
<div class="red material-icons" *ngIf="action.status == 'pending'">pending_actions</div>
<div class="blue material-icons" *ngIf="action.status == 'queued'">pending</div>
<div class="yellow material-icons" *ngIf="action.status == 'error'">error</div>
</mat-panel-description>
<mat-panel-description fxFlex="40%">{{action.key}}</mat-panel-description>
<div *ngFor="let dataItem of action?.data | keyvalue">{{dataItem?.value?.message}}
</div>
<!-- <mat-panel-description>{{action.startDate | date:'medium'}}</mat-panel-description>-->
</mat-expansion-panel-header>
</div>
</mat-expansion-panel>
</mat-accordion>
<ng-template #loading>Loading…</ng-template>
</div>
when I do {{dataItem?.value?.message}} I get nothing. When I do dataItem.value, I get the values for both count and message.
I need only the value from message. What am I doing wrong??
with keyvalue pipe on your object it will convert the action.data object to below array
[{key:count, value: 9}, {key:message,value:'9 sites synced'}]
if you iterate over the above object :
dataItem?.value?.message = undefined
dataItem.value = 9 and 9 sites synced
Which is what u r seeing.
You can just add a condition when binding the value what to show
{{ dataItem.key === 'message' ? dataItem.value: ' '}}
there are other ways also...I think you can figure out now what was happening and what needs to be done as per your requirement.
I'm trying to display all the reply from this json :
https://www.reddit.com/r/AskReddit/comments/k8w43d/people_with_the_last_name_pepper_who_have.json
So, depending of the post im loading and the reply, my number of children will differ. How can I loop throught it until I reach the last reply with children (body[2].data.children) ?
Like this :
<div class="replies-box" *ngFor="let reply of comments.body[1].data.children">
<div class="reply-header">
<p class="reply-author"><b>From</b> : {{ reply.data.author }}</p>
<p class="reply-send"><b>Send</b> : {{ this.getDateReply(reply.data.created_utc) }}</p>
</div>
<div class="text-first-reply" [innerHTML]="this.getHtmlDecode(reply.data.body_html)">
</div>
</div>
I have only the first level of reply, is there a way to simply loop through them all ?
Thanks in advance.
I would use a recursion type of approach.
Develop a app-comment component and if comment has children, loop over the children and display the app-comment. That way it will loop over the comments until no more children
<div *ngIf='comment'>
<span *ngIf='comment.kind; else showComment'>Kind: {{ comment.kind }}</span>
<ng-template #showComment>
<span>{{ comment }}</span>
</ng-template>
<div>
<app-comment *ngFor='let child of comment.data?.children' [comment]='child'> </app-comment>
</div>
</div>
See this sample illustration
Simply use ngFor inside ngFor with help of ng-container (will not create extra dom elements)
<div class="replies-box">
<ng-container *ngFor="let commentBody of comments.body">
<ng-container *ngFor="let reply of commentBody.data.children">
<div class="reply-header">
<p class="reply-author">
<b>From</b> : {{ reply.data.author }}
</p>
<p class="reply-send">
<b>Send</b> : {{ this.getDateReply(reply.data.created_utc) }}
</p>
</div>
<div class="text-first-reply" [innerHTML]="this.getHtmlDecode(reply.data.body_html)">
</div>
</ng-container>
</ng-container>
</div>
Have a array of objects and to iterate through each object to display it on HTML.Need to add an line breaker if a specific key is repeated.
var arr = [{color: red},{fruit: grapes},{city: Bangalore} {ice-cream: chocolate},{color: yellow},{fruit: orange},{color: pink}]
Tried code
<div class="bx--row" *ngFor="let obj of arr; let i = index;">
<ng-container *ngFor="let item of obj | keyvalue">
<span class="bx--col-xs-5 bx--col-md-5"> {{item.key}} :</span>
<span class="bx--col-xs-5 bx--col-md-5">{{item.value}} </span>
</ng-container>
</div>
Expected output :
color: red
fruit:grapes
city: Bangalore
ice-cream: chocolate
//line breaker/space here before having key "color" repeating
color: yellow
fruit: orange
color: pink
unexpected output:
I am not exactly sure what you're after, but you could check if the property is color using *ngIf directive.
<div class="bx--row" *ngFor="let obj of arr; let i = index; let first = first">
<ng-container *ngFor="let item of obj | keyvalue">
<ng-container *ngIf="item.key === 'color' && !first">
<br />
</ng-container>
<span class="bx--col-xs-5 bx--col-md-5"> {{item.key}} :</span>
<span class="bx--col-xs-5 bx--col-md-5">{{item.value}} </span>
</ng-container>
</div>
Working example: Stackblitz
Update
<div class="bx--row" *ngFor="let obj of arr; let i = index; let first = first">
<ng-container *ngIf="obj.color && !first">
<br />
</ng-container>
<ng-container *ngFor="let item of obj | keyvalue">
<span class="bx--col-xs-5 bx--col-md-5"> {{item.key}} :</span>
<span class="bx--col-xs-5 bx--col-md-5">{{item.value}} </span>
</ng-container>
</div>
I developed a gallery of images separated by several categories.
I just want to display categories that contain images.
I have three categories: "new", "old", "try".
Of these three categories, only new and old have images. My problem is that all categories are appearing, even those that have no image (as is the case with try).
Is there a way to present only the categories that contain images?
How can I do this?
DEMO
code
<div *ngFor="let cat of Cats">
<div class="row ">
<span class="">{{cat}}</span>
</div>
<ul class="mdc-image-list my-image-list" style="padding-left: 10px;padding-right: 10px;">
<ng-container *ngFor="let product of data; let j = index;">
<li class="mdc-image-list__item" *ngIf="product.Cat == cat">
<div class="mdc-image-list__image-aspect-container">
<ng-container *ngIf="product.image == null; else productImage">
<img src="./assets/image-not-found.svg" class="mdc-image-list__image imagenotfound">
</ng-container>
<ng-template #productImage>
<img [src]="product.image" class="mdc-image-list__image">
</ng-template>
</div>
</li>
</ng-container>
</ul>
</div>
The try should not be presented :(
You can wrap your category div in an <ng-container>, and then use *ngIf to check if your data array contains a product in a given category. The best way to achieve that is to have an array with product counts per given category.
Add this to your AppComponent class:
get counts() {
return this.data.reduce((obj, value) => {
if (value.Cat in obj) {
obj[value.Cat]++;
} else {
obj[value.Cat] = 1;
}
return obj;
}, {});
}
And then use this as your template:
<ng-container *ngFor="let cat of Cats">
<div *ngIf="counts[cat]">
<div class="row ">
<span class="">{{cat}}</span>
</div>
<ul class="mdc-image-list my-image-list" style="padding-left: 10px;padding-right: 10px;">
<ng-container *ngFor="let product of data; let j = index;">
<li class="mdc-image-list__item" *ngIf="product.Cat == cat">
<div class="mdc-image-list__image-aspect-container">
<ng-container *ngIf="product.image == null; else productImage">
<img src="./assets/image-not-found.svg" class="mdc-image-list__image imagenotfound">
</ng-container>
<ng-template #productImage>
<img [src]="product.image" class="mdc-image-list__image">
</ng-template>
</div>
</li>
</ng-container>
</ul>
</div>
</ng-container>
You can write format function, write data as an object where the key is category, value is array of images and use keyvalue pipe.
For example:
component property: formattedData: {[key: string]: string[]} = {}
format function:
formatData(data: {image: string; cat: string}[]): void {
data.forEach((item: {image: string; cat: string}) => {
if (this.formattedData[item.cat]) {
this.formattedData[item.cat].push(item.image)
} else {
this.formattedData[item.cat] = [item.image]
}
});
}
call the format function in constructor:
constructor() {
this.formatData(this.data);
}
template:
<div *ngFor="let item of formattedData | keyvalue">
<div class="row">
<span class="">{{item.key}}</span>
</div>
<ul class="mdc-image-list my-image-list" style="padding-left: 10px;padding-right: 10px;">
<ng-container *ngFor="let image of item.value;">
<li class="mdc-image-list__item">
<div class="mdc-image-list__image-aspect-container">
<img [src]="image ? image : './assets/image-not-found.svg'" class="mdc-image-list__image" [ngClass]="{'imagenotfound': !image}">
</div>
</li>
</ng-container>
</ul>
</div>
I think it looks better because we have a little less logic in the template. You have only listed categories that have images.