Problem with displaying array length correctly - html

In an Angular project, I want to loop through filterLifePolicies array because I want to pass via URI the LobDsc property.
The problem is that I also want to output as a number the length of the array but because I loop through each element if the array contains e.g.
3 objects, 3 cards are displayed...I only want one card with the number 3 (array length).
HTML:
<div class="card" *ngFor="let policy of filterLifePolicies">
<a [routerLink]= "['/contracts', policy.LobDsc]"
routerLinkActive="active" class="noLinksDecoration">
<div class="card-body text-center">
<img src="../../assets/images/Component62_1.svg">
<p class="policyTitle">Ζωή & Υγεία</p>
<p class="counter">{{countLife}}</p>
</div>
</a>
</div>
Part of Typescript:
getCustomerPolicies () {
this.http.get<any>('http://localhost:8080/o/mye/pol').subscribe({
next: res => {
this.filterLifePolicies = res.Life.Policies;
console.debug(this.filterLifePolicies);
this.countLife = this.filterLifePolicies.length;

You can do the following, considering countLife variable is assigned the required value.
<div class="card">
<ng-container *ngFor="let policy of filterLifePolicies; index as i">
<a *ngIf="i < 1" [routerLink]="['/contracts', policy.LobDsc]" routerLinkActive="active" class="noLinksDecoration">
<div class="card-body text-center">
<img src="../../assets/images/Component62_1.svg">
<p class="policyTitle">Ζωή & Υγεία</p>
</div>
</a>
</ng-container>
<p class="counter">{{countLife}}</p>
</div>
In the above code snippet, ng-container is being used to iterate through filterLifePolicies in order to access LobDsc value. Since the iteration should not create duplicate HTML div elements with CSS class card-body, an additional check via ngIf is being used to check the index value, such that it should be always lesser than 1.
Although if the LobDsc value is the same for all the values of filterLifePolicies, the recommended approach would be to fetch its value via the dot notation and store it in a variable that can be later binded directly to your template during runtime.

Related

Skip array element in HTML

I have an array of length 5 on which I'm looping over to create the rating scale as shown in the image below. How can I skip iterating over the first element (1) of the array and only render the div for the last four elements of the array (2, 3, 4, 5). I tried slicing the array first and then render but it doesn't help. Is there any way that the element remains in the array and I can skip over it in the HTML.
<div class="rating-type__pipe" #messageEl [attr.data-option-id]="opt._id" id="rating_id_right{{opt?._id}}"
*ngFor="let opt of positiveArray; index as i">
<div class="rating-type__pipe-pillar">
<span [ngStyle]="{'height': (i+1)*(100/positiveArray.length)+'%','opacity': (i+1)*(1/positiveArray.length)}" class="rating-type__pipe-pillar-bg"></span>
</div>
<div class="rating-type__pipe-text">{{opt.text}}</div>
</div>
You can use slice method to skip first element.
<div class="rating-type__pipe" #messageEl [attr.data-option-id]="opt._id" id="rating_id_right{{opt?._id}}"
*ngFor="let opt of positiveArray.slice(1); index as i">
<div class="rating-type__pipe-pillar">
<span [ngStyle]="{'height': (i+1)*(100/positiveArray.length)+'%','opacity': (i+1)*(1/positiveArray.length)}" class="rating-type__pipe-pillar-bg"></span>
</div>
<div class="rating-type__pipe-text">{{opt.text}}</div>
</div>
I created a dummy div for the first element and now it works fine.

Angular Property binding ngForTrack not used by any directive

I'm working on converting an angular 1.x site to angular 2.6 and I'm trying to get some text and a URL to showup and I've got the following code from the old site :
<div ng-repeat="item in cartCtrl.downloadFinishedItems track by $index">
<div class="links-14">
<a ng-show="item.downloadJob.downloadLink"
ng-click="cartCtrl.downloadFile(item)">{{item.name}}</a>
</div>
</div>
But when I convert to :
<div *ngFor="let item of downloadFinishedItems track by $index">
<div class="links-14">
<a [hidden]="!item.downloadJob.downloadLink"
(click)="downloadFile(item)">{{item.name}}</a>
</div>
</div>
I get the following error :
Is the new equivalent of that line? :
<div *ngFor="let item of downloadFinishedItems; index as i; trackBy:i">
As mentioned in the NgForOf documentation:
To customize the default tracking algorithm, NgForOf supports trackBy
option. trackBy takes a function which has two arguments: index and
item. If trackBy is given, Angular tracks changes by the return value
of the function.
In your case, it would be:
<div *ngFor="let item of downloadFinishedItems; trackBy: trackByIndex">
with the method:
trackByIndex(index, item) {
return index;
}

How to show/hide in Angular2

I have a component that show/hide element by clicking a button.
This is my html
<div *ngFor="let history of histories | sortdate: '-dateModified'">
<p><b>{{ history.remarks }}</b> - <i>{{history.dateModified | date:'short'}}</i></p>
<a href="google.com"
[class.datatable-icon-right]="history.$$expanded"
[class.datatable-icon-down]="!history.$$expanded"
title="Expand/Collapse Row"
(click)="toggleExpandRow(history)"></a>
<!-- hide/show this by clicking the button above.-->
<div *ngFor="let step of history.steps; let i = index">
<b>{{i+1}}.</b> {{step}}
<span class="clear"></span>
</div>
<hr />
</div>
and my .ts
toggleExpandRow(row) {
console.log('Toggled Expand Row!', row);
//row
return false;
}
trying to search but, can't find any same sample.
On jquery, I can do this, but on Angular2, I am having hard time to figure this.
There are two options:
1- You can use the hidden directive to show or hide any element
<div [hidden]="!edited" class="alert alert-success box-msg" role="alert">
<strong>List Saved!</strong> Your changes has been saved.
</div>
2- You can use the ngIf control directive to add or remove the element. This is different of the hidden directive because it does not show / hide the element, but it add / remove from the DOM. You can loose unsaved data of the element. It can be the better choice for an edit component that is cancelled.
<div *ngIf="edited" class="alert alert-success box-msg" role="alert">
<strong>List Saved!</strong> Your changes has been saved.
</div>
Use the ngIf in your repeated rows. Create a boolean property called showStep to indicate whether the row should be expanded or not.
<div *ngFor="let step of history.steps; let i = index" ngIf="history.showStep">
<b>{{i+1}}.</b> {{step}}
<span class="clear"></span>
</div>
Then, in your .ts file:
toggleExpandRow(history) {
history.showStep = !history.showStep
//note the same porperty of showStep that is used in your html
}
Extra:
In fact, to save a few lines of codes, you don't even need the toggleExpandRow function at all. You can do it inline in your html:
//other attributes omitted for brevity
<a (click)="history.showStep = !history.showStep">

Can you use a ngFor with a modulus operator in Angular 2

I'm writing out images to the web page. Every three images I would like to start a new row. Does angular 2 support this?
You can achieve it by doing following:
<div *ngFor="let t of temp(math.ceil(arr.length/3)).fill(); let i = index" class="row">
<div *ngFor="let item of arr.slice(3*i,3*i + 3);" class="item">
{{item}}
</div>
</div>
And in your component:
export class App {
temp = Array;
math = Math;
arr= [1,2,3,4,5,6,7,8,9,10,11];
}
Here's working Plunker
You can access the index of the iteration from the *ngFor like so:
*ngFor="let x of container; let i = index;"
you can then reference that index in an *ngIf inside of the *ngFor to display your new row:
<div *ngIf="i%3 === 0">
Borrowing from both answers, but leaning more on Alex's, here's how I accomplished it in ng2 (v2.0.1).
<template ... is deprecated. Where you see <template ... you should use <ng-template ... after v5.
<template ngFor let-peer [ngForOf]="peers" let-p="index" let-last="last">
<div class="row" *ngIf="p % 2 === 0">
<div class="col-xs-8 col-sm-6">
<label><input type="checkbox" ... {{peers[p].name}}</label>
</div>
<div class="col-xs-8 col-sm-6" *ngIf="!last">
<label><input type="checkbox" ... {{peers[p+1].name}}</label>
</div>
</div>
</template>
Note that while I get each item from the collection, let-peer [ngForOf]="peers", I don't specifically use it. Instead I use the collection and the index, let-p="index", adding to the index as needed, e.g., peers[p] and peers[p+n].
Adjust your modulus as needed. The last row should check to be sure that the first column to the last column is not the last item in the iterable.

How to loop through array upto only some objects using ngFor in angular 2

I'm looping through an array which has 6 objects and using ngFor where I want to loop only up to 4 elements .. How Can I do that??
<div class="item active" *ngFor="#data of lengthArray">
content
</div>
In LengthArray I have 6 but how to loop up to 4 records only??
and also I want to loop from 4th record to 6th record in another div.. How can I start from 4th record??
You can use the slice pipe with a start and end parameter. The start parameter is required and the end parameter is optional.
<div class="item active" *ngFor="#data of lengthArray | slice:start[:end]">
content
</div>
You can capture the index and then make it less then 4
<div class="item active" *ngFor="#data of lengthArray;i=index">
<div *ngIf="i<=4">
content
</div>
</div>
I haven't really tested the code but you can find a lot of examples here on stackoverflow, do more researching...
Angular 2: how to apply limit to *ngFor?
More about filters...
How to apply filters to *ngFor
Simple solution:
<tr *ngFor=""let obj of ArrayogObjs; let i=index">
<td *ngIf="i<4">
{{obj.name}}
</td>
</tr>