Variable in html ,angular - html

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>

Related

How to assign a starting index value while using ngFor in angular

I have a requirement to always display minimum of 5 rows(5 or more rows) in a table. For example, if there are 2 rows available in Database, I need to display other 3 more rows in UI with empty rows.
Here is what I tried so far:
<div *ngFor="let task of tasks; let i = index">
<div class="rowDiv">{{task.id}}</div>
</div>
Here I want to run the loop from i = tasks.size to i < = 5. So that I have total of 5 rows in UI. How to achieve this?
<div *ngFor=" let i = index">
<div class="rowDiv"></div>
</div>
You can loop over an array of 5 items, and use *ngIf to display an additional row if no data item exists at a given index:
<div *ngFor="let task of tasks">
<div class="rowDiv">{{task.id}}</div>
</div>
<ng-container *ngFor="let i of [0,1,2,3,4]">
<div *ngIf="!tasks[i]">
<div class="rowDiv">This row is empty</div>
</div>
</ng-container>
See this stackblitz for a demo.
you can also add so many rows you need after
<table>
<row *ngFor="let task in task">
</row>
<!--if task.length<5-->
<ng-container *ngIf="tasks.length<5">
<!-use slice:0:5-tasks.length-->
<row *ngFor="let i of [0,1,2,3,4] |slice:0:5-tasks.length">
</row>
</ng-container>
</table>
You don't need to keep this logic in html.
In you class you can do something like this: (suppose you fetch tasks from server)
this.getTasks().subscribe((tasks) => {
const emptyTasks = Array(5).fill({id: 'empty'});
this.tasks = tasks.map((t, index) => t || emptyTasks[index]);
})
This could be better handled in the controller. In case of default change detection strategy, the template is reloaded multiple times without our control or knowledge. So it's better to make sure the tasks variable has atleast 5 elements in the controller rather than to control the flow in the template. You could something like the following in the controller and leave the template unchanged.
for (let i = 0; i < 5; i++) {
if(!this.tasks[i].id) {
this.tasks[i].id = '';
}
}

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>

display multiple nested data with angular6

I'm receiving JSON data from an API which has some child objects as well. The API has a menu level and down the menu, it's having meals. What I want to do is to display meals relating to each menu under the menu
JSON from API
[{"id":6,"name":"Menu 1","serveDate":"2019-05-10","meals":[{"id":13,"name":"Rice with Stew","description":"rice","image":"","mealType":"BREAKFAST","unitPrice":5,"status":"ENABLED"}]},{"id":5,"name":"Menu 2","serveDate":"2019-06-10","meals":[{"id":13,"name":"Corn Flakes,"description":"Flakes","image":"","mealType":"BREAKFAST","unitPrice":5,"status":"ENABLED"}]},{"id":4,"name":"Menu 3","serveDate":"2019-07-10","meals":[]}]
HTML
<div *ngFor="let item of menuList">
<h2>Menu</h2>
{{item.name}} - {{item.servate}}
<h2 *ngFor="let item of menuList.meals">Meals</h2>
{{item.name}} - {{item.mealType}}
</div>
JS
getMenus() {
this.menuServices.menuList(this.pagedData)
.subscribe(
response => {
if (response && response.code === HttpStatus.OK) {
this.menuList = response.data;
}
},
);
}
Any help on how to make this work correctly the way it should work?
<div *ngFor="let menu of menuList">
<h2>Menu</h2>
{{menu.name}} - {{menu.servate}}
<h2>Meals</h2>
<ng-container *ngFor="let meal of menu.meals">
{{meal.name}} - {{meal.mealType}}
</ng-container>
</div>
Using this way you don't have to add unnecessary divs or any other html tag for looping in angular.
this is the perfect way to do nested loops without changing your html
No need to access the main list as you have your meals array in the item object.
Change HTML Code to:
<div *ngFor="let item of menuList">
<h2>Menu</h2>
{{item.name}} - {{item.servate}}
<h2>Meals</h2>
<div *ngFor="let item of item.meals">
{{item.name}} - {{item.mealType}}
</div>
</div>
When you're doing something like let item of menuList that means the item variable should be used to refer to an individual item within your loop. To avoid confusion, I'd also recommend naming these item vars for nested loops differently.
Another important thing to keep in mind that all the markup that you want to be output for each array item should be wrapped with an element with *ngFor. It's not the case with your <h2> tag being printed for each meal, but not the meal description.
Edit the template as follows:
<div *ngFor="let menuItem of menuList">
<h1>Menu</h1>
<h2>{{menuItem.name}} - {{menuItem.serveDate}}</h2>
<p>maybe description here</p>
<h3>Meals</h2>
<p *ngFor="let mealItem of menuItem.meals">{{mealItem.name}} - {{mealItem.mealType}}</p>
</div>

Why don't the String values get displayed as HTML tags using innerHTML?

I get string data from my database to my variable, I want to display them as HTML tags by [innerHTML], but it doesn't work.
The variable is displayed on string instead HTML Tags.
I tried to use with DomSanitizer but it don't work:
article:Article[];
(article.articlesTitleHtml:SafeHtml;)
in the function:
this.article.forEach(elementArticle => {
elementArticle.articlesTitleHtml = this.sanitizer.bypassSecurityTrustHtml(elementArticle.articleTitle)
});
in HTML page:
<div *ngFor="let item of articles">
<div id="{{item.articleId}}">
<h2 class="chart" [innerHTML]="item.articlesTitleHtml"></h2>
</div>
my code:
in Type Script:
articles:Article[];
ngOnInit() {
this.apiArticle.getArticleList().subscribe(data=>{
this.articles=data
})
in HTML page:
<div *ngFor="let item of articles">
<div id="{{item.articleId}}">
<h2 class="chart" [innerHTML]="item.articleTitle"></h2>
</div>
</div>
It should work, you can check here...
if you can share the type of data that you're dealing with, it will give more insight into the appropriate DomSanitizer method which should be called
in my example above, i used both bypassSecurityTrustHtml & bypassSecurityTrustUrl for the 2 different types of strings which needed sanitization

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.