Don't render if array is empty - Angular *ngFor - json

I'm building up a Frontend with JSON Data.
I have to go trough a lot of arrays to check if a value exists inside. If the Value doesn't exist, then my complete HTML shouldn't render.
<ng-container *ngIf="document161['_source']['161_Events']">
<div class="row">
<span class="col-md-auto meta-object text-muted"><span>Begräbnistag:</span></span>
<span class="col">
<span *ngFor="let event of document161['_source']['161_Events']">
<span *ngFor="let sub of event.peventsub">
<ng-container *ngIf="sub.content === 'Begräbnis'">
<span *ngFor="let geburtsort of event.pstdatetypesub">
{{geburtsort.content}}
</span>
</ng-container>
</span>
</span>
</span>
</div>
<mat-divider class="my-2"></mat-divider>
</ng-container>
What i have already tried is:
<ng-template #thenBlock>
<ng-container *ngIf="document161['_source']['161_Events']">
<div class="row">
<span class="col-md-auto meta-object text-muted"><span>Begräbnistag:</span></span>
<span class="col">
<span *ngFor="let event of document161['_source']['161_Events']">
<span *ngFor="let sub of event.peventsub">
<ng-container *ngIf="sub.content === 'Begräbnis'">
<span *ngFor="let geburtsort of event.pstdatetypesub">
<ng-container ngIf="*ngIf="geburtsort.content; then thenBlock else elseBlock">
{{geburtsort.content}}
</ng-container>
</span>
</ng-container>
</span>
</span>
</span>
</div>
<mat-divider class="my-2"></mat-divider>
</ng-container>
</ng-template>
<ng-template #elseBlock>
</ng-template>
But as you can see there are multiple problems. Maybe Ii can't reach the ngIf condition if the value doesn't exist. And the then else logic doesn't work inside a ng-container template.
What should be the best solution?

try this
*ngIf="document161?._source?.161_Events?.length > 0"
If array having values it will show that element else will hide same.

Related

How to subscribe unsubscribe in angular from one button click?

I have a button for subscribe/unsubscribe. In case of subscribtion it calls userSubscribtions() function but what i want is when the user clicks on unsubscibe after that. It should run the delSubscription function defined in my component. And selected tab is the tab which I am viewing on my front-end.
Is there any way to do so? Below is my html code and I have those two functions in the component.
<button matRipple type="button" class="btn btn-outline-success my-sm-0 mx-2 d-flex shadow-none"
(click)="userSubscribtions(selectedTab)" [disabled]="this.loading">
<ng-container *ngIf="User.subscriptions.indexOf(selectedTab) == -1">
<span class="material-icons">notifications</span>
Subscribe
</ng-container>
<ng-container *ngIf="User.subscriptions.indexOf(selectedTab) != -1">
<span class="material-icons">notifications_off</span>
Unsubscribe
</ng-container>
</button>
You need to have a container function that should decide what to call. Modify you html like this:
<button matRipple type="button" class="btn btn-outline-success my-sm-0 mx-2 d-flex shadow-none"
(click)="handleSubscriptions(selectedTab, User.subscriptions.indexOf(selectedTab) == -1)" [disabled]="this.loading">
<ng-container *ngIf="User.subscriptions.indexOf(selectedTab) == -1">
<span class="material-icons">notifications</span>
Subscribe
</ng-container>
<ng-container *ngIf="User.subscriptions.indexOf(selectedTab) != -1">
<span class="material-icons">notifications_off</span>
Unsubscribe
</ng-container>
</button>
And then in your component file:
handleSubscriptions(selectedTab: number, isSubscribe: boolean) {
if(isSubscribe) {
// Call userSubscribtions method
} else {
// call delSubscription method
}
}

How to display a certain HTML if a condition is never met (Angular)

Say I had an ngFor loop surrounding an ngIf statement
<ng-container *ngFor="let item of items">
<ng-container *ngIf="condition1">
//display table1
</ng-container>
</ng-container>
Now, say I had a second table (call it table2) that I want to display if table1 is not displayed.
<ng-container *ngIf="condition1 was never met and table1 is not displayed">
//display table2
<ng-container>
What is the best way to do this, and is there a way to do this using Angular's data binding features? Or, could you point me in the right direction?
You can use standard Angular ngIf, Else like this 👇
<ng-container
*ngIf="condition1; then table1; else table2">
</ng-container>
<ng-template #table1>
<div>
table1
</div>
</ng-template>
<ng-template #table2>
<div>
table2
</div>
</ng-template>
You can read more about it on this post
You can use the ng-template and ngIf-else
<ng-container *ngFor="let item of items">
<ng-container *ngIf="condition1;else table2">
//display table1
</ng-container>
</ng-container>
<ng-template #table2> //display table2 </ng-template>
or
<ng-container *ngFor="let item of items">
<ng-container *ngIf="condition1;then table1 else table2"> </ng-container>
</ng-container>
<ng-template #table1> //display table1 </ng-template>
<ng-template #table2> //display table2 </ng-template>

How do I implement directive (ng-template) in Angular?

In my HTML file, I've duplicated the "elseBlock2". How do I implement directive (ng-template) to handle it?
<div class="col-2">
<ng-container *ngIf="item.isSuccess; else elseBlock2">
{{getSimplifiedSize(item.file.size)}}
</ng-container>
<ng-container *ngIf="item.progress; else elseBlock2">
{{item.progress}}%
<mat-progress-bar mode="determinate" color="primary" value={{item.progress}}></mat-progress-bar>
</ng-container>
</div>
Can work something like this?
<div class="col-2">
<ng-container *ngIf="(item.isSuccess || item.progress); else elseBlock2">
<ng-container *ngIf="item.isSuccess">
{{getSimplifiedSize(item.file.size)}}
</ng-container>
<ng-container *ngIf="item.progress">
{{item.progress}}%
<mat-progress-bar mode="determinate" color="primary" value={{item.progress}}></mat-progress-bar>
</ng-container>
</ng-container>
<ng-template #elseBlock2>
Your content
</ng-template>
</div>
Update:
If you want to display the elseBlock only when it's both not in progress and success you can do something like this:
<div class="col-2">
<ng-container *ngIf="item.isSuccess">
{{getSimplifiedSize(item.file.size)}}
</ng-container>
<ng-container *ngIf="item.progress">
{{item.progress}}%
<mat-progress-bar mode="determinate" color="primary" value={{item.progress}}></mat-progress-bar>
</ng-container>
<ng-container *ngIf="!item.progress && !item.isSuccess">
Your content
</ng-container>
</div>
You can use if then else with ternary operator to achieve else-if in Angular
<ng-container
*ngIf="item.isSuccess then successBlock; else (item.progress) ? progressBlock : elseBlock"
></ng-container>
<ng-template #successBlock>
{{ getSimplifiedSize(item.file.size) }}
</ng-template>
<ng-template #progressBlock>
{{ item.progress }}%
</ng-template>
<ng-template #elseBlock>
Error
</ng-template>
In else statement, instead of passing a template, do another conditional check with ternary operator and pass other two templates as values

Angular - How to add a counter Variable from template to html property?

I have this HTML:
<ng-container *ngFor="let something of things; let i = index">
<span data-e2e="{{"abc" + i}}" class="checkmark"></span>
</ng-container>
I want to have this result rendered in the DOM:
<span data-e2e="abc0" class="checkmark"></span>
<span data-e2e="abc1" class="checkmark"></span>
...
But this {{"abc" + i}} wont work.
"abc" should be a string.
How can I do this, without saving the property (counter: i) to the components controller
You should change,
<ng-container *ngFor="let something of things; let i = index">
<span data-e2e="{{"abc" + i}}" class="checkmark"></span>
</ng-container>
To:
<ng-container *ngFor="let something of things; let i = index">
<span [attr.data-e2e]="'abc'+i" class="checkmark"> {{something}} </span>
</ng-container>
Here you should use attr as prefix and need to assign the value to custom attribute using property binding like, [attr.data-e2e]="'abc'+i"..
Working Stackblitz..
You should change:
<span data="normalString{{i}}" class="checkmark"></span>
normalString should be outside {{}}
also data attribute is not correct, read more how to properly add custom data attribute:
https://www.w3schools.com/tags/att_global_data.asp

Editable field saved to database

I've got this editable field. I need it to save the new data and store it in the database.
HTML:
<ng-container *ngIf="groupedVolumes">
<ng-container *ngFor="let model of groupKeys() | slice:-3" >
<tr>
<th class="model">{{ carValues(model)[0].model }}</th>
<ng-container *ngFor="let value of carValues(model)">
<td contenteditable='true' class="data">
{{ value.scheduledVolume }}
</td>
</ng-container>
</tr>
</ng-container>
</ng-container>
The HTML data shows the editable field.
This is the button to save with:
<div class="row">
<div class="col-auto">
<button
type="submit"
class="btn btn-success mx-1"
onclick="saveData()">Save
</button>
</div>
</div>
This is not a good approach.
Use input (probably type="text") for input using the angular form api, then you can store the new values in database on completion.