display multiple nested data with angular6 - html

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>

Related

Angular - Project different content with only one ng-content in an *ngFor

I'd want the ngfor to use one child component per iteration :
Card component, <card> :
<div *ngFor="let item of items">
<ng-content [value]="item">
</ng-content>
</div>
Use of the card component :
<card>
<child-comp1> Hello </child-comp1>
<child-comp2> Goodbye </child-comp2>
<child-comp3> See you </child-comp3>
...
</card>
Expected result :
<card>
<child-comp1> Hello item1</child-comp1>
<child-comp2> Goodbye item2</child-comp2>
<child-comp3> See you item3</child-comp3>
...
</card>
Of course there should be as much child components as data in the ngFor array for it to work correctly.
EDIT : the above exemple doesn't represent the actual datas and components used, it is only here to illustrate and explain the question.
There could be more or less than 3 child components and they are more complex than just displaying values.
I will try to help you.
First of all I created a main class that will call all the card components.
main.component.html
<div *ngFor="let item of items">
<app-card [values]="item">
</app-card>
</div>
main.component.ts
you only need to have your data here, for instance:
items: string[][] = [['it1.1','it1.2','it1.3'],['it2.1','it2.2','it2.3'],['it3.1','it3.2','it3.3']];
and in your card component:
card.component.html
<ul>
<li>Hello {{values[0]}}</li>
<li>Goodbye {{values[1]}}</li>
<li>See you {{values[2]}}</li>
</ul>
card.component.ts
(Import Input is required)
import { Component, OnInit, Input } from '#angular/core';
#Input() values: string[] = [];

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>

ng-select multi select checkbox in angular 7

what I want to do is when I check an item the div of that item appears
for example if I select Crédit bancaire and Compte courant associé.
the two divs corresponding to these items are displayed
Here is the example:
https://stackblitz.com/edit/angular-d163sn?file=src%2Fapp%2Fapp.component.ts
here is a simple workaround, try changing bindValue from id to name
and change this code
<div>
<div *ngIf=" selected == 1">Crédit bancaire</div>
<div *ngIf=" selected == 2">Compte courant Associe</div>
<div *ngIf=" selected == 3">Fonds Propres</div>
</div>
to this
<div *ngFor="let item of selected | keyvalue">
<h1>{{item.value}}</h1>
</div>
the idea is to store that object to an iterable object, but keep in mind we need to use keyValue pipe to make it work with ngFor.

Display key and array values using *ngFor in angular 9

JSON
{
"cars":
{
"12345": [1960, 1961, 1962],
"4567": [2001, 2002]
}
}
HTML
<strong>Plate and year</strong>
<div *ngFor="let list of lists">
{{list.cars}}
</div>
I need to display like this:
Plate and year
12345- 1960, 1961, 1962.
4567- 2001, 2002.
Based on your data structure, you can achieve this using the KeyValuePipe and additional nested *ngFor. KeyValuePipe allows you to iterate over an object similar to Object.entries providing a key and value property for each item. In this case the value will be an array that you can iterate over using an *ngFor:
<strong>Plate and year</strong>
<div *ngFor="let list of lists">
<div *ngFor="let car of list.cars | keyvalue">
<div>{{car.key}} - <div *ngFor="let year of car.value">{{year}}</div>
</div>
</div>
</div>
Here is an example in action.
Hopefully that helps!

Angular - css style changes in the list of objects in *ngFor

I have two components, parent:
<ng-container *ngIf="itemList != null">
<div *ngFor="let item of itemList">
<component-item [componentItem]="item"></component-item>
</div>
</ng-container>
and child (component-item):
<div class="row myClass" [ngClass]="{'selected': isSelected }" (click)="method()">
...
</div>
As a result I have list of items. I have two css styles: default and "selected". I would like to change styles of items after clicking on them like: when I click on the first item it should change to "selected" and then after clicking second item it should change to "selected" and the first one return to the default. My variable "isSelected" is a boolean type and I change its value on "true" in "method()". How can I change its value on "false" when I select another item from the list?
Try like this, it may work
In component.ts File
cssEnabled:any="";
private method(itemName:string)
{
this.cssEnabled=itemName;
}
In compontent.html :
<div class="row myClass" [ngClass]="{'selected': componentItem==cssEnabled}" (click)="method(componentItem)">
...
</div>