how to set html class or id dynamically using angular - html

<div class="container">
<div class="container__usernamesContainer">
<a class="container__usernamesContainer--text" *ngFor="let user of getUsers()">
Username: {{ user.getUsername() }}
</a>
</div>
<div class="container__statusesContainer">
<span class="container__statusesContainer--text" *ngFor="let status of getUsers()">
<span [ngClass]="'{{ user.getUsername() }}'">
Status: {{ status.getStatusLabel() }}
</span>
</span>
</div>
</div>
i am trying to set [ngClass]="'{{ user.getUsername() }}'" dynamically, and i do not get the value. how can i achive that?

There are two things going on here. You have two different *ngFor loops both iterating over the array returned by getUsers(). One you do let users of getUser(), and the other you do let status of getUsers(). But you then try to uncalled user instead of status in the second loop. Below is what your code should be.
<div class="container">
<div class="container__usernamesContainer">
<a class="container__usernamesContainer--text" *ngFor="let user of getUsers()">
Username: {{ user.getUsername() }}
</a>
</div>
<div class="container__statusesContainer">
<span class="container__statusesContainer--text" *ngFor="let status of getUsers()">
<span [ngClass]="status.getUsername()">
Status: {{ status.getStatusLabel() }}
</span>

As you are using property binding you don't need to use interpolation:
[ngClass]="user.getUsername"
You just need to bind the property that you want to use

Related

Restructure the display of instantiated elements in *ngFor

I am currently just adding randomized numbers to an array and displaying them to the user.
<div *ngFor="let temp of randomIntArray; let i = index">
<div *ngIf="i == randomIntArray.length - 1">
This is the real random number {{ temp }}
<div>
<button (click)="addRandomValueIntoRandomIntArray()">
add random number
</button>
</div>
</div>
<div *ngIf="i != randomIntArray.length - 1">
{{ temp }}
</div>
</div>
I think I understand what's happening here as I am creating a new element on the DOM each time the user clicks : addRandomValueIntoRandomIntArray() as its increasing the length of the randomIntArray.
Due to the: *ngIf="i == randomIntArray.length - 1 this will always be the last element and will be always be displayed at the bottom. Is there any feasible way for me to to swap them around and have all the new elements created at the bottom going downwards instead? Below is an image of how it currently looks.
You can reverse the order of ngFor items using randomIntArray.slice().reverse()
and you need to change ngIf condition to i==0.
app.component.html
<div *ngFor="let temp of randomIntArray.slice().reverse(); let i = index">
<div *ngIf="i ==0">
This is the real random number {{ temp }}
<div>
<button (click)="addRandomValueIntoRandomIntArray()">
add random number
</button>
</div>
</div>
<div *ngIf="i != randomIntArray.length - 1">
{{ temp }}
</div>
</div>

How to use image url stored in Firestore

I have an image uploaded to Firestore storage which I want to display on my website. I am then storing the url for this image in my Firestore document:
I can successfully reference the data for this document and all the others in the collection, then display in my html as so:
<ng-container *ngIf="infinite | async as products">
<cdk-virtual-scroll-viewport itemSize="100" (scrolledIndexChange)="nextBatch($event, (products[products.length - 1].data.productName))">
<div class="product-row" fxLayout="row wrap" fxLayout.xs="column wrap" fxFlexFill fxLayoutAlign="center center">
<div fxFlex.gt-xs="50%" fxFlex.gt-md="30%" *cdkVirtualFor="let p of products; let i = index; trackByIndex">
<mat-card class="product-tile">
<img class="product-thumbnail" src="p.data.thumbnail" [routerLink]="p.id">
<div class="product-brand">
{{ p.id }}
</div>
<div class="product-details">
<span id="product-name">{{ p.data.productName }}</span> <span id="product-price">{{ p.data.price }}</span>
</div>
<div class="add-to-pad-button">
<button (click)="openDialog(p.id)" mat-raised-button color="accent">Add to Pad</button>
Click Me
</div>
</mat-card>
</div>
</div>
</cdk-virtual-scroll-viewport>
</ng-container>
In theory, I would assume that calling the reference to thumbnail, which is the image URL, would result in the image being displayed. However, the result is:
Am I incorrectly referencing the image URL?
Change p.data.thumbnail to {{ p.data.thumbnail }}

highlight word by start and end matches using angular 7

I have a collection of array which is having datas like
[0]: username {kavya} secret {password}
[1]: lorem ipsem text data value
[2]: lorem {{lrm}} datas {{pp}}
I am using foreach to show this data in frontend with
<div *ngFor="let data of output;let i=index">
<div *ngIf="data.includes('{') || data.includes('{{');else isNotEdited;" >
<div class="variable-textarea" contenteditable="false" >
<span>
{{data | slice:' ' }}
</span>
</div>
</div>
<ng-template #isNotEdited>
<ngx-md>{{data}}</ngx-md>
</ng-template>
</div>
Here I achieved like 0,2 row of div will be editable and in case of 1st array is non-editable.
But I want to do like specific matches which word starts with { or {{ and that particular word needs to be highlight and editable.
Is there any option to do in this way
Thanks in advance.
You could split the data into words:
<div *ngFor="let data of arr">
<span *ngFor="let word of data.split(' ')">
<span *ngIf="word.indexOf('{') > -1;else isNotEdited;">
<span class="variable-textarea-2" contenteditable="true">
{{word | slice:' ' }}
</span>
</span>
<ng-template #isNotEdited>
<span class="variable-text-2" contenteditable="false">
{{word}}
</span>
</ng-template>
</span>
</div>
Check this Stackblitz example I made based on your code: https://stackblitz.com/edit/angular-pkg6i9
this is a performance nightmare, you don't want to be running this many functions in template, and your format isn't helping you. map your data ahead of time into a friendlier view model:
this.mappedOutput = this.output.map(data => {
const editable = data.includes('{'); // checking for doubles is redundant
return {
editable,
data: !editable
? data
: data.split(' ')
.map(word => ({
word,
editable: word.trim().startsWith('{') && word.trim().endsWith('}')
}))
};
})
run this whenever your output changes, then use it in template:
<div *ngFor="let data of mappedOutput;let i=index">
<div *ngIf="data.editable;else isNotEdited;" >
<div class="variable-text">
<ng-container *ngFor="let word of data.data">
<div *ngIf="word.editable; else wordTmp" class="variable-textarea inline" contenteditable="true" >
<span>{{word.word}}</span>
</div>
<ng-template #wordTmp>
{{word.word}}
</ng-template>
</ng-container>
</div>
</div>
<ng-template #isNotEdited>
<ngx-md>{{data.data}}</ngx-md>
</ng-template>
</div>
and adjust the styles by adding this to your css:
.variable-textarea.inline {
display: inline-block;
width: fit-content;
margin: 0;
}
here's an edited blitz: https://stackblitz.com/edit/angular-arayve?file=src/app/app.component.html

How to print something only on he first item when parsing using ng-repeat?

So I have a ng-repeat which I am parsing through an array propRentDetail. It prints out some divs with the property name and its rent.
I have also used orderBy : '-trent', so that it shows the property first which has the highest rent and goes down. Now, I have an up arrow icon from fontAwesome and I was trying to show that only with the first property div (i.e. the one with the highest rent). So how do I show something only for the first item?
<div ng-repeat = "summ in propRentDetail | orderBy: '-trent'">
<p>{{ summ.propname }}</p>
<p>{{ summ.proprent }}</p>
</div>
Use $first like this:
<div ng-repeat = "summ in propRentDetail | orderBy: '-trent'">
<div ng-if="$first">icon</div>
<p>{{ summ.propname }}</p>
<p>{{ summ.proprent }}</p>
</div>
inside ng-repeat, AngularJS expose a variable named $first, its value is type boolean which refers if the item is first on the list.
<div ng-repeat = "summ in propRentDetail | orderBy: '-trent'">
<i class="fa fa-arrow" ng-if="$first"></i>
<p>{{ summ.propname }}</p>
<p>{{ summ.proprent }}</p>
</div>
You can also use $index if you want
<div ng-repeat = "summ in propRentDetail | orderBy: '-trent'">
<i class="fa fa-arrow" ng-if="$index === 0"></i>
<p>{{ summ.propname }}</p>
<p>{{ summ.proprent }}</p>
</div>
Other variables available inside ng-repeat:
$last
$even
$odd

In Angular 7 when two buttons are nested the second one is ignored

In some Angular 7 template I have two button (click) nested. The second one is unclikable : the first one only answer the (click).
How may I set the second button clickable ?
This html code comes from an Angular 5 course : https://openclassrooms.com/fr/courses/4668271-developpez-des-applications-web-avec-angular/5091266-creez-une-application-complete-avec-angular-et-firebase
<button
class="list-group-item"
*ngFor="let book of books; let id = index"
(click)="onViewBook(id)">
<h3 class="list-group-item-heading">
Titre : {{ book.title }}
<!-- ignored code starts here -->
<button class="btn btn-default pull-right"
(click)="onDeleteBook(book)">
<span class="glyphicon glyphicon-minus"></span>
</button>
<!-- end of ignored code -->
</h3>
<p class="list-group-item-text">
Auteur : {{ book.author }}</p>
</button>
Nesting buttons is not valid in HTML like commented before by #ConnorsFan.
Instead, change the first button to div. This way your UX + UI will work perfectly.
<div
class="list-group-item"
*ngFor="let book of books; let id = index"
(click)="onViewBook(id)">
<h3 class="list-group-item-heading">
Titre : {{ book.title }}
<!-- ignored code starts here -->
<button class="btn btn-default pull-right"
(click)="onDeleteBook(book)">
<span class="glyphicon glyphicon-minus"></span>
</button>
<!-- end of ignored code -->
</h3>
<p class="list-group-item-text">
Auteur : {{ book.author }}</p>
</div>