Get Key from Object - Angular 7 - html

I have this object:
this.item = {
name:"Michael",
age:18
};
I want to put on HTML
name: Michael
age: 18
<div >{{ item (name) }}</div> --??? should put name
<div>{{ item.name }}</div>
<div ">{{item (age)}}</div> --?? should put age
<div>{{ item.age}}</div>
How can I get the string name and age from the object?

Use keyValue pipe
<div *ngFor="let item of item | keyvalue">
{{item.key}}:{{item.value}}
</div>
stackblitz
You should avoid calling a function (which some suggest in comments) inside template. If you do that, that function will be called every time change detection runs. Which is bad. Almost always prefer pipes over method call inside the template.

You can try something like:
<div *ngFor="let key of item">
<div>{{key}}: {{item[key]}}</div>
</div>

Related

Variable in html ,angular

I am working on an app in angular and in an html file i have something like this
<div *ngFor="let var of list">
<div>
{{newVar.name}}
<div>
</div>
My problem is that i dont know how to declare newVar properly in the div because i want newVar to be a result returned from a function in the component that takes the first var as parameter
so i basically want something like
newVar=func(var)
before using the name attribute and i dont know how to do this
I could do func(var).name but i dont only display the name so i dont want to call the function multiple times
So your workaround is something like , streaming list in html and passing var to typescript function func(var) storing result in newVar. From there you want to display name value in UI . Is my understanding is correct , my suggestion is
ts
newVar = [];
///
func() {
list.forEach(element=>{
newVar.push(element);
});
}
html
<div *ngFor="let var of newVar">
<div>
{{var.name}}
<div>
</div>
Currently there aren't any direct solution for this. One workaround is to use *ngFor as a hack (and the cost is performance)
<div *ngFor="let _var of list">
<div *ngFor="let newVar of [func(_var)]">
{{newVar.name}}
</div>
</div>
you has severals options:
<div *ngFor="let var of list">
{{func(var).name}}
</div>
Use an auxiliar array
//in your .ts
auxArray:any[]=[];
this.auxArray=this.list.map(x=>this.func(x))
//and iterate over auxArray
<div *ngFor="let var of auxArray">
{{var.name}}
</div>
//or iterate over list and use "index"
<div *ngFor="let var of list;let i=index">
{{var}} = {{auxArray[i].name}}
</div>
If your list is an array of object you can also
//in your .ts
this.list.forEach(x=>{
data:this.func(x)
}
//and iterate over list but use data.name
<div *ngFor="let var of list">
{{var.data.name}}
</div>
The first option has a poor efficency because Angular execute the function several times -each time check the application, you can see if use a console.log(var) in your function
You can pass variables to newvar function like this.
<div *ngFor="let var of list">
<div> {{newVar(var)}} <div>
</div>
i have found a solution,basically you can do something like
<div *ngIf="func(var) as newVar">
{{newVar.name}}
</div>

low performance in binding function in view

i have an ionic 4 with angular app, im also implemented websocket in my componentA.
componentA.html:
<div *ngFor="let item of myList">
<div>{{ item.name }}</div>
<div>{{ calcPrice(item.price) }}</div>
<div>{{ calcDistance(item.distance) }}</div>
<div>{{ calcAge(item.age) }}</div>
<div>{{ setColor(item.color,item.name) }}</div>
</div>
here a sample of myList:
[
{...},
{...},
{...},
{...},
...
]
myList is an array and normaly contain 20 items, those items is updated with my websocket. I faceing a big performance issue when i enter the page, my app completely freeze when my list passes aproximately 8 items, so a started do to a big research and i discovery that using functions on view is a bad pratice
articles: here and here
Every function that i uses have a return and I need those function do make calculations and etc, putting this inside html will make the code dirty and hard to maintein.
what i shoud do to make this work propertly? should i use pipes for each item?
Edit:
here is one of the functions that i used in my html
calcVolum(item) {
if (
TestClass.startsWithA(item.name) &&
!this.needHelp(item.name)
) {
return (
Number(item.price.replace(this.regexPts, '')) *
Number(item.currentQuantity) *
item.age
);
} else if (this.needHelp(item.name)) {
return (
Number(item.price.replace(this.regexPts, '')) *
Number(item.currentQuantity) *
item.dolptax *
item.age
);
}
return (
Number(item.price.replace(this.regexR$, '').replace(',', '.')) *
item.currentQuantity
);
}
you set up your component so that things are run when they need to be run.
write a function like:
calculateItemValues(items) {
return items.map(i => {
return Object.assign({}, i,
{
priceCalc: this.calcPrice(i.price);
// however many else you need
}
);
});
}
call that whenever you need to (when the items change), maybe like this.calcItems = this.calculateItemValues(this.items) or inside an rxjs map statement is usually a great place, and iterate the calculated:
<div *ngFor="let item of calcItems">
<div>{{ item.name }}</div>
<div>{{ item.priceCalc }}</div>
<!-- whatever else you set -->
</div>

Is there a way to use iteration inside an object in html in angular?

Here's how my html code is looking:
<div *ngFor="let historyArticle of historyArticles; let i=index">
<div [innerHTML]='historyArticle[i].fields.text | mdToHtml'></div>
</div>
I want to target the every object inside the historyArticle array. Writing {{i}} inside a div gives me the index number for each entry but I want to use that to target the correct text field in each entry
You don't need the i index at all in this case. historyArticle itself is the object you want:
<div *ngFor="let historyArticle of historyArticles">
<div [innerHTML]='historyArticle.fields.text | mdToHtml'></div>
</div>
Using *ngFor in Angular is basically looping through an array.
So doing :
for (let i = 0; i < this.historyArticles.length; i++) {
// do something e.g console.log(this.historyArticles[i].fields.text);
}
Is pretty much the same as :
<div *ngFor="let historyArticle of historyArticles">
<span>{{ historyArticle.fields.text }}</span>
</div>
Hope it helps you understand that in this case you don't need to use i = index
try this.
<div *ngFor="let historyArticle of historyArticles; let i=index">
<div>{{historyArticle[i].fields.text | mdToHtml}}</div>
</div>

Reference ngFor value in component

I have a nested ngFor statement. I need to retrieve the value of my first ngFor on button click.
I have tried the following:
use template reference variable
use attribute binding
use Input decorator
This is my code:
<mat-expansion-panel *ngFor="let item of Datasource;">
<mat-expansion-panel-header style="display:flex" class="mat-row">
{{item.Header}}
</mat-expansion-panel-header>
<mat-selection-list [(ngModel)]="selectedOptions">
<mat-list-option *ngFor="let line of item.match; let i= index;" [value]="line">
<div class="container-name">
<div class="col-6">{{i}} - {line.user.Name }} vs {{ line.user.Address }}</div>
</mat-list-option>
</mat-selection-list>
<div style="text-align:center; padding: 20px">
<button mat-raised-button color="primary" (click)="submit()" type="submit">Add</button>
</div>
</mat-expansion-panel>
Can this be achieved?
Well, you need to clone that object properties first. As that object is linked to the template, when you manipulate it, it is manipulated on template too. You can use var obj = Object.assign({}, actual obj) and then do the manipulation on obj instead of actual one. Then it will not get affected in template. Hope it helps.

Use ng-model to add class to all previous childrens Angular JS

Here is my html code:
<div ng-repeat="(key, a) in items" data-id="{{ Id }}" class="item" id="{{Key}}" ng-click="item($event, key)">
<div class="bubble></div>
<p>
<span> {{ description }}</span>
</p>
</div>
This is the list of items. When we click on the item in the list - all previous elements are set as active (add class).
Here is how it's done:
$scope.item = function(event, key) {
var current;
if ( $(event.target).hasClass('bubble')){
current = $(event.target).closest('#'+ Key);
changeItem(current);
}
function changeItem(current){
$(current).addClass('active');
$(current).prevAll().addClass('active');
$(current).nextAll().removeClass('active');
}
};
Is it possible to use ng-model or something else to set the active value by default form json file? Mean, in json - we have item 3 - marked as active, so how could I add this value to the $scope.item as current? or probably use ng-model?
I have not tried it, but something like this should work.Assuming that the class has to be applied to ng-repeat div. Change your ng-repeat div to:
<div ng-repeat="(key, a) in items" data-id="{{ Id }}" class="item" id="{{Key}}" ng-click="markSelected($index)" ng-class="{'active':selectedIndex<$index}">
</div>
The ng-click call a method markSelected($index) on the controller that sets the currently selected item index. The ng-class uses the current index ($index) and the selectedIndex to determine what class to apply.
The final task is to implement the function which looks like:
$scope.markSelected=function(index) {
$scope.selectedIndex=index;
}
You should stop using jquery and start to think in a more angular way.
There is a directive ng-class that is used to add or remove classes
You can find more information here : https://docs.angularjs.org/api/ng/directive/ngClass
<div ng-repeat="(key, a) in items" data-id="{{ Id }}" class="item" id="{{Key}}" ng-click="item(key)">
<div ng-class="{active : a.active, inactive : a.inactive}"></div>
<p>
<span> {{ description }}</span>
</p>
</div>
$scope.item = function(key){
$scope.items[key].active = true;
$scope.items[key].inactive = false;
}