Hide element using ngFor and ngIf - html

I want to hide the other 3 elements in li element after the one of the list was clicked (the clicked list remain unhide), as I try it hide all the li element.
payment.component.ts
paymentLists = [
{
name: 'IpayEasy',
},
{
name: 'Credit Card',
},
{
name: 'Internet Banking',
},
{
name: '7-Eleven',
},
];
selectedIndex: number;
select(index:number) {
this.selectedIndex = index;
}
payment.component.html
<ul *ngIf="selectedIndex == paymentList">
<li (click)="select(paymentList)"
*ngFor="let paymentList of paymentLists; let i=index">
<span>{{paymentList.name}}</span>
</li>
</ul>
Here what have I tried,
demo
Before:
IpayEasy
Credit Card
Internet Banking
7-Eleven (clicked li)
After:
7-Eleven (li element remain unhide)

You need to update your template as following
Move ngFor to ng-container element
Update ngIf condition to be true only if there is no selected index or the matching selected index
Pass index in select function
Updated html will be as follows
<ul>
<ng-container *ngFor="let paymentList of paymentLists; let i=index" >
<li (click)="select(i)" *ngIf="selectedIndex === undefined || selectedIndex == i" [ngClass]="{'tab__list--selected--mobile': selectedIndex == paymentList}">
<span>{{paymentList.name}}</span>
</li>
</ng-container>
</ul>
For reference, here is the working version

try
<ul *ngIf="selectedIndex == paymentList">
<ng-container *ngFor="let paymentList of paymentLists; let i=index">
<li (click)="select(paymentList)" *ngIf="!selectedIndex || selectedIndex=i">
<span>{{paymentList.name}}</span>
</li>
</ng-container>
</ul>

you can use this code instead of yours :
your ts:
select(index) {
this.paymentLists = [index];
}
your HTML:
<ul *ngIf="selectedIndex == paymentList">
<li (click)="select(paymentList)"
*ngFor="let paymentList of paymentLists; let i=index">
<span>{{paymentList.name}}</span>
</li>
</ul>

Just for the record, Since my previous answer wasn't very clear. Here is a thorough explanation to the solution for the aforementioned problem.
paymentLists = [
{
name: 'IpayEasy',
},
{
name: 'Credit Card',
},
{
name: 'Internet Banking',
},
{
name: '7-Eleven',
},
];
selectedIndex: number;
select(index:number) {
this.selectedIndex = this.paymentLists.findIndex(x => x.name==paymentListNameObject.name);
this.paymentListSelected = true;
}
in the above mentioned code, the select function recieves an object instead of the index number. which can be corrected as above. Also i added a variable paymentListSelected. this variable tracks if a particular payment method has been selected.
In the HTML, you could get rid of *ngIf="selectedIndex == paymentList" and use the following:
<ul>
<li *ngFor="let paymentList of paymentLists; let i=index" (click)="select(paymentList)"
[ngClass]="{'tab__list--selected--mobile': ((i == selectedIndex)&&paymentListSelected),'hide-tab__list--unselected--mobile': paymentListSelected}">
<span>{{paymentList.name}}</span>
</li>
</ul>
Here i add 2 classes tab__list--selected--mobile which is applied to the selected payment method based on the index number which was selected by the user. And to hide the other options, i added hide-tab__list--unselected--mobile to all other options.
Finally here is a working link just in case the explanation wasn't clear enough.
https://stackblitz.com/edit/angular-display-list-d19ffv
This answer i guess qualifies for not getting DELETED!!!!!

Related

Display content of a list in Angular 2?

I am new in Angular. I am creating a component in which I am creating a list of int. An example of the content of the list is 13,14,15,22,23,24.
I want to display this content on screen in a specific way. I want the continiously integeres to be in one line and the others in the second line. For example I want this:
13:00, 14:00, 15:00 button
22:00, 23:00, 24:00 button
I am trying this but I don't want a continious list, I want two parts of the list.
<ul>
<li *ngFor="let int of listindexdisabled">{{int}}:00 </li>
</ul>
Can someone help?
Why don't we try to set up two loops with a SlicePipe to iterate on a portion ( 13 -> 15 and second loop 2 -> 24 )?
If you have non dynamic list and you list will always need to be cut at a certain index , this should help you
https://angular.io/api/common/SlicePipe
<ul>
<li *ngFor="let int of listindexdisabled | slice:0:3">
{{int}}:00
</li>
</ul>
<ul>
<li *ngFor="let int of listindexdisabled | slice:3:6">
{{int}}:00
</li>
</ul>
otherwise , i think that this should works
<ul>
<ng-container *ngFor="let int of listindexdisabled">
<li *ngIf="int < 22">
{{int}}:00
</li>
</ng-container>
</ul>
<ul>
<ng-container *ngFor="let int of listindexdisabled">
<li *ngIf="int > 21">
{{int}}:00
</li>
</ng-container>
</ul>
You can try this below code
<ul>
<li *ngFor="let int in listindexdisabled">{{int}} : 00</li>
</ul>
Here is a sample of what you could do: repro on Stackblitz
And in case stackblitz is not working, here is the code :
.html :
<ul *ngFor="let chunk of displayedValues">
<li>
<span *ngFor="let value of chunk">{{value}}:00 - </span>
</li>
</ul>
.ts :
import { Component, OnInit } from '#angular/core';
import { getAttrsForDirectiveMatching } from '#angular/compiler/src/render3/view/util';
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent implements OnInit {
values = [13,14,15,18,19,22,23,24];
displayedValues = [];
ngOnInit(){
this.customChunk();
}
customChunk(){
let array = [];
this.values.forEach(val => {
if(array.length === 0
|| val === array[array.length-1] + 1){
array.push(val);
} else {
this.displayedValues.push(array);
array = [];
}
});
// add the last chunk
this.displayedValues.push(array);
}
}
The idea is to rework your array into an array of chunk made by numbers that follow themselves. Then you just have to do a loop inside a loop to display your values.

change background color based on response attributes Angular

I had request data from API, then I got response Object, so using *ngFor, I had managed to display some data that I want, problem is that are some css need to be implemented based on response attribute, for my data, I had list of bank and status. based on attribute status Offline
I need to change background color and need only show Offline status only.I had managed to change the background color, this is what I had tried:
html file
<ul class="ul1">
<li
[style.background]="getBackgroundColor(p.status)"
class="li1" *ngFor="let p of myData?.paymentChannels">
<span>{{p.name}}</span>
<br>
<span>{{p.status}}</span>
</li>
</ul>
ts file
getBackgroundColor(status) {
switch (status) {
case 'Offline':
return 'grey';
}
}
expected output:
also this is my stackblitz demo, I could use some suggestion to solve mine.
I would suggest something like this:
<ul class="ul1">
<li
[ngClass]="{offline: p.status == 'Offline'}"
class="li1" *ngFor="let p of myData?.paymentChannels">
<span>{{p.name}}</span>
<br>
<span> {{p.status == 'Offline' ? p.status : ' '}}</span>
</li>
</ul>
And add to css:
.offline {
background-color: gray;
}
your code is working but I think it's better without function like this:
<ul class="ul1">
<li [style.background]="'grey' : p.status == 'Offline'" class="li1"
*ngFor="let p of myData?.paymentChannels">
<span>{{p.name}}</span>
<br>
<span>{{p.status}}</span>
</li>
</ul>
Before
<span>{{p.status}}</span>
After
<span>{{p.status === 'Offline' ? 'Offline' : ' '}}</span>
It would be even better if you would extract the logic to a method withing the TS file.
The ' ' part is a placeholder (blank space) so the box do not collapse, but I would recommend adding the proper CSS styling, for instance, adding min-height: 36px; to the class .li1 would suffice.
StackBlitz
You can filter your data using structural directive *ngIf and then apply styling:
<ul
*ngIf="myData?.paymentChannels"
class="ul1">
<li
[style.background]="p?.status === 'Offline'? 'grey' : 'green'"
class="li1"
*ngFor="let p of myData?.paymentChannels">
<ng-container *ngIf="p?.status === 'Offline'">
<span>{{p.name}}</span>
<br>
<span>{{p.status}}</span>
</ng-container>
</li>
</ul>
If you want to filter and your array of data is small, then you can use *ngIf directive. However, it would be better to use filter pipe:
<li *ngFor="let item of myData?.paymentChannels | yourFilter:filterargs">
and your pipe:
import { Pipe, PipeTransform } from '#angular/core';
#Pipe({
name: 'myfilter',
pure: false
})
export class YourFilterPipe implements PipeTransform {
transform(items: any[], filter: Object): any {
if (!items || !filter) {
return items;
}
// filter items array, items which match and return true will be
// kept, false will be filtered out
return items.filter(item => item.title.indexOf(filter.title) !== -1);
}
}
and you should include your pipe into app.module.ts:
import { YourFilterPipe } from './shared/pipes/your-filter.pipe';
#NgModule({
imports: [
..
],
declarations: [
YourFilterPipe,
],
providers: [
..
],
bootstrap: [AppComponent]
})
export class AppModule { }
Please, see the example at stackblitz.com
UPDATE:
If you do not want to filter data, but hide status offline you can use *ngIf structural directive:
<ul
*ngIf="myData?.paymentChannels"
class="ul1">
<li
[style.background]="p?.status === 'Offline'? 'grey' : 'green'"
class="li1"
*ngFor="let p of myData?.paymentChannels">
<span>{{p.name}}</span>
<br>
<span *ngIf="p?.status === 'Offline'; else empty">{{p.status}}</span>
<ng-template #empty>$nbsp;</ng-template>
</li>
</ul>

Angular 6 :material checkbox checked all checkbox in loop

In loop
<li *ngFor="let item of verticalList;let i=index;">
<mat-checkbox [(ngModel)]="checked" name="i">Checked</mat-checkbox>
</li>
I want to give each checkbox a different checked value. How to do it?
I don't know what is verticalList type, but id you use a list of object you could do something like this:
verticalList = [
{
name: 'foo',
checked: false
},
{
name: 'foo1',
checked: false
},
{
name: 'foo2',
checked: false
}
]
<li *ngFor="let item of verticalList;let i=index;">
<mat-checkbox [(ngModel)]="item.checked" name="i">Checked {{ item.name }}</mat-checkbox>
</li>

Expand/collapse list items in recursive tree menu in angular

How can i achieve that my nested lists expand on click?
At the moment it just opens the first level.
sidebar.component.html
<ul>
<ng-template #recursiveList let-list>
<li *ngFor="let item of list" (click)="listClick($event, item)">
{{item.name}}
<ul *ngIf="item.folders?.length > 0" [ngClass]="{ 'subfolder': selectedItem == item }">
<ng-container *ngTemplateOutlet="recursiveList; context:{ $implicit: item.folders }"></ng-container>
</ul>
</li>
</ng-template>
<ng-container *ngTemplateOutlet="recursiveList; context:{ $implicit: list }"></ng-container>
</ul>
Click from sidebar.component.ts
listClick(event, newValue) {
console.log(newValue);
this.selectedItem = newValue;
}
The first level works like it should. I click on the folder name and it expands. But when I click on the list element on the next level the list collapses instead of expanding further.
I think the event is bubbling up to the parent i.e. when you click on a child, you are also clicking on the parent element too. Adding event.stopPropagation() should stop the event bubbling to the parent. I.e.
listClick(event, newValue) {
console.log(newValue);
this.selectedItem = newValue;
event.stopPropagation();
}
Update: I am not sure how your data is being fetched, so I am not sure if this is 100% right. But here is a working example of how it should work (you do need the event.stopPropagation();) I have added && item.showSubfolders the *ngIf which gets toggled on click:
<ul>
<ng-template #recursiveList let-list>
<li *ngFor="let item of list" (click)="listClick($event, item)">
{{item.name}}
<ul *ngIf="item.folders?.length > 0 && item.showSubfolders" [ngClass]="{ 'subfolder': selectedItem == item }">
<ng-container *ngTemplateOutlet="recursiveList; context:{ $implicit: item.folders }"></ng-container>
</ul>
</li>
</ng-template>
<ng-container *ngTemplateOutlet="recursiveList; context:{ $implicit: list }"></ng-container>
</ul>
And the Listclick:
listClick(event, newValue) {
console.log(newValue);
this.selectedItem = newValue;
newValue.showSubfolders = !newValue.showSubfolders
event.stopPropagation()
}
working example: https://stackblitz.com/edit/angular-emz37r

Angular 2 dynamic expendable nested lists

I have this dynamic list created with ngFor. When I click on item I want to expand it with new dynamic list, but only for that item. In my following code it expends for every item in the first list. I understand why that is happening, but I don't have ideas how to solve it.
Here is my code
<ul *ngFor="let p of portList">
<li (click)="setONUList(p.name)" id="{{ p.name }}"><img src="app/resources/{{ p['oper-status'] }}.png" class="myimage"/>{{ p.name}}</li>
<ol *ngFor="let onu of portONUList">
<li><img src="app/resources/{{ onu['oper-status'] }}.png" class="myimage" />{{ onu.name}}</li>
</ol>
</ul>
Any ideas how to solve this would be very helpful.
From what I understand, the subarray is the same which is shown for all your items, so there is no relation between the nested array and the outer array.
My suggestion would actually be to add a new property in your array, e.g expanded... so e.g your outer array would look like:
portList = [{id:1,name:'one',expanded:false},{id:2,name:"two",expanded:false}];
And then your HTML:
<ul *ngFor="let p of portList">
<li (click)="expand(p)">{{ p.name}}</li>
<div *ngIf="p.expanded">
<ol *ngFor="let onu of portONUList">
<li>{{ onu.name}}</li>
</ol>
</div>
</ul>
And on click, toggle the expanded property:
expand(p: any) {
p.expanded = !p.expanded;
}
Of course if you want to have a "quick" solution you could rely on HTML5 with no need of the new property:
<details *ngFor="let p of portList">
<summary>{{p.name}}</summary>
<ul *ngFor="let onu of portONUList">
<li>{{ onu.name}}</li>
</ul>
</details>
Here's a plunker with both options.
There should be a relation between parent and childlist and the list should be in json format. Refer below code
<ul>
<li ng-repeat="item in parent" ng-click="showChilds(item)">
<span>{{item.name}}</span>
<ul>
<li ng-repeat="subItem in item.subItems" ng-show="item.active">
<span>{{subItem.name}}</span>
</li>
</ul>
</li>
</ul>
Sample JSON FORMAT
let parent= [
{
name: "Item1",
subItems: [
{name: "SubItem1"},
{name: "SubItem2"}
]
},
{
name: "Item2",
subItems: [
{name: "SubItem3"},
{name: "SubItem4"},
{name: "SubItem5"}
]
},
{
name: "Item3",
subItems: [
{name: "SubItem6"}
]
}
];