I have the following block of code in the front-end:
<li *ngFor = "let cat of this.dataCategory.iconTitleSet" (click)="getTypeFromCategory(cat.title)" class="list-group-item puntero">
<img [src]="cat.icon" alt="icon" title="icon" />{{cat.title}}
</li>
in the component:
getTypeFromCategory(tipo: string) {
this.typeItem = tipo.toLowerCase();
if (this.arrayTipo.includes(this.typeItem)) {
const i = this.arrayTipo.indexOf( this.typeItem );
this.arrayTipo.splice( i, 1 );
} else {
this.arrayTipo.push(this.typeItem);
}
}
in synthesis what up to now does is add a value that I get from FRONTEND in an array in case it is not, and if it eliminates it from the array, but when I add it I also want to put a specific style, for example a yellow background, but this last I do not know how to do it, I do not know how to say to angular that I put a specific style in element "li" specific generated by an "ngfor" loop when I click on the element.
this is the image in the frontend
You can do it in some ways:
1. to set a diffrennt class with [ngClass]="" to each li and style in css
for example:
<li *ngFor = "let cat of this.dataCategory.iconTitleSet;let i=index;" [ngClass]="'title_'+i" (click)="getTypeFromCategory(cat.title)" class="list-group-item puntero">
<img [src]="cat.icon" alt="icon" title="icon" />{{cat.title}}
</li>
in css:
.title_1{}
2. you can set it with [ngStyle] or style.
<li *ngFor = "let cat of this.dataCategory.iconTitleSet;let i=index;" [style.color]="cat.color" (click)="getTypeFromCategory(cat.title)" class="list-group-item puntero">
<img [src]="cat.icon" alt="icon" title="icon" />{{cat.title}}
</li>
You can do the following.
HTML
<li *ngFor = "let cat of this.dataCategory.iconTitleSet; let i = index" (click)="getTypeFromCategory(cat.title, index)" class="list-group-item puntero" [class.changeColor]="i == selectedValue">
<img [src]="cat.icon" alt="icon" title="icon" />{{cat.title}}
Component
selectedValue: any;
getTypeFromCategory(tipo: string, index) {
this.selectedValue = index;
this.typeItem = tipo.toLowerCase();
if (this.arrayTipo.includes(this.typeItem)) {
const i = this.arrayTipo.indexOf( this.typeItem );
this.arrayTipo.splice( i, 1 );
} else {
this.arrayTipo.push(this.typeItem);
}
}
class changeColor will be applied to every list item selected.
Related
Is there a way to include button in this code which will with click make the same change to an array the same way [ngStyle] does in the following part of the code?
app.component.html
<div class="styling">
<ul>
<li *ngFor = "let a of arr"
[ngStyle]="changeFont()">
{{a}}
</li>
</ul>
</div>
app.component.ts
arr=['car','house','beach','microphone'];
changeFont(){
return {'font-size.px':15}
}
In Angular you has variables in .ts, and use this variables in the .html.
An example
style:any=null //declare a variable
toogleStyle() //A function that change the variable
{
if (!this.style)
this.style={'font-size':'15px';color:'red'}
else
this.style=null
}
You can use
<div (click)="toogleStyle()" [ngStyle]="style">click me!</div>
And see how change the style
As you has "severals" <li> you need severals variables if you want severals<li> can be "selected" at time or an unique variable if only one <li> can be selected at time.
The "severals variables" are an Array, so to change one element of
the array you need pass the "index" of the array
styles:any[]=[]
toogleStyle(index:number) //A function that change the variable
{
if (!this.styles[index])
this.styles[index]={'font-size':'15px';color:'red'}
else
this.styles[index]=null
}
<ul>
<!--see using let i=index, i becomes value 0,1,2,3...->
<li *ngFor = "let a of arr;let i=index"
<!--see you pass the "index" to the function-->
[ngStyle]="styles[i]" (click)="toogleStyle(i)">
{{a}}
</li>
</ul>
The unique variable is a number that is the "index" selected. For no
selected index, the variable becomes -1 (Remember that 0 is the fisrt
element of the array)
selectedIndex:number=-1
toogleStyle(index:number) //A function that change the variable
{
if (this.selectedIndex==index) //if you click on selected <li>
this.selectedIndex=-1;
else
this.selectedIndex=index;
}
<ul>
<li *ngFor = "let a of arr;let i=index"
<!--you use the conditional operator (condition)?
value if condition is true:
value if condition is false
-->
[ngStyle]="i==selectedIndex?
{'font-size':'15px';color:'red'}:
null"
(click)="toogleStyle(i)">
{{a}}
</li>
</ul>
I am creating a tree menu, visually it looks like this:
The tree has been created based on an array of objects obtained from a service, extracted from a date property.
Now, I have to get the tree menu to allow displaying and collapsing the: years, months and complete dates, in the style of this component:
https://angular2-tree.readme.io/
Ideally, I'd do this with typescript, but if it's hard for me, I'd try using an external component.
This is the html code:
<ul>
<li *ngFor="let y of tree | keyvalue">{{y.key}}
<ul>
<li *ngFor="let m of tree[y.key] | keyvalue">{{m.key}}
<ul>
<li *ngFor="let d of tree[y.key][m.key] | keyvalue">{{d.key}}
<ul>
<li *ngFor="let h of tree[y.key][m.key][d.key]"><a [ngClass]="{'hourSelected': (idSchedule === h.id || lastId === h.id),'hourUnSelected': idSchedule !== h.id}" (click)="loadMacroProcesses(h.id)">{{h.hour}}</a></li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
This would be the solution, now I will refine it:
<ul>
<li id="year" *ngFor="let y of tree | keyvalue; let i=index" (click)="listClick($event, i)">{{y.key}}
<ul [hidden]="indexExpandedYear!=i?true:null">
<li id="month" *ngFor="let m of tree[y.key] | keyvalue; let j=index" (click)="listClick($event, j)">{{m.key}}
<ul [hidden]="indexExpandedMonth!=j?true:null">
<li id="day" *ngFor="let d of tree[y.key][m.key] | keyvalue; let k=index" (click)="listClick($event, k)">{{d.key}}
<ul [hidden]="indexExpandedDay!=k?true:null">
<li *ngFor="let h of tree[y.key][m.key][d.key]"><a [ngClass]="{'hourSelected': (idSchedule === h.id || lastId === h.id),'hourUnSelected': idSchedule !== h.id && lastId !== h.id}" (click)="loadMacroProcesses(h.id)">{{h.hour}}</a></li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
This is the typescript method:
listClick(event, i) {
switch (event.srcElement.id) {
case "year":
this.indexExpandedYear = this.indexExpandedYear==i?-1:i;
event.stopPropagation();
break;
case "month":
this.indexExpandedMonth = this.indexExpandedMonth==i?-1:i;
event.stopPropagation();
break;
case "day":
this.indexExpandedDay = this.indexExpandedDay==i?-1:i;
event.stopPropagation();
break;
default:
break;
}
}
Can you recommend me a good one external component? Thanks.
NOTE: I am working with version 11 of Angular
NOTE: If you deploy one year, the rest of the years should be collpased back.
NOTE: Angular material is not valid for me
You could add a parameter for visibility and click event to the parent ul. How it would work is that they would have a boolean value on them for visibility that would change when you click the top ul element. You would have a method that would just switch between true/false and display if true hidden if false. Click event should be on the top li element and visibility on its child.
You should checkout the tree component provided by primeng. It has its own data format and can do your own customisation on top it.
I have an array of items that need to be displayed based on roles. I need the first value which will fulfil the ngIf condition.
I am adding my code below:
My Array(kind of how it will originally look):
parentTabList = [
{
name: 'abc',
label: 'abc',
icon : 'question_answer',
role : ['vend_perm','vend_temp','vend_subs']
},
{
name: 'xyz',
label: 'xyz',
icon : 'question_answer',
role : ['vend_perm','vend_subs']
}
]
My Html: -
<ng-container *ngFor="let form of parentTabList let i = index">
<li *ngIf="form.role.includes(userRole)">
<a (click)="methodName(form)">
{{form.label}}
</a>
</li>
</ng-container>
UserRole is a string value that I get when a user logs-in.
I need to add a ngClass to the anchor tag if it is the first anchor to be displayed.
(I am a noob at StackOverflow, please let me know if any more explanation is required).
You can identify first element of the array with index.
But as per my understanding you need filter this array with roles and then apply ngClass to first element from filtered list.
So add method to return filtered array with respect to roles
In Template:
filterParentTabList(parentList: any) {
return parentList.filter(form => form.role.includes(this.userRole));
}
In View:
<ng-container *ngFor="let form of filterParentTabList(parentTabList); let i = index">
<li>
<a [ngClass]="{ 'addYourClaaName': i === 0 }" (click)="methodName(form)">
{{form.label}}
</a>
</li>
</ng-container>
Happy Coding.. :)
You can write like this. In this code, f represents the first position of your array.
<ng-container *ngFor="let form of parentTabList; let i = index; let f = first">
<li *ngIf="f">
<a (click)="methodName(f)">
`{{f.label}}`
</a>
</li>
</ng-container>
If you want other position of your array, you can write like you mentioned above.
You can define a getter that will get you the index. This can then be used in the html
get firstIndex() {
return this.parentTabList.indexOf(this.parentTabList.find(({role}) =>
role.includes(this.userRole)))
}
Now in your html
<ng-container *ngFor="let form of parentTabList let i = index">
<li *ngIf="form.role.includes(userRole)">
<a [ngClass]="{redText: firstIndex === i}" (click)="methodName(form)">
{{form.label}}
</a>
</li>
</ng-container>
See Stackblitz Demo Here
I have a simple list:
<ul id="list">
<li id="item-1">1</li>
<li id="item-2" style="display: none">2</li>
<li id="item-3">3</li>
<li id="item-4">4</li>
<li id="item-5">5</li>
</ul>
And need to get index of a specific item disregarding hidden items.
var list = document.getElementById('list');
var items = list.querySelectorAll('li:not([style*="display: none"])');
I try to convert NodeList in Array:
var list_items = Array.from(items);
But don't known how to run something like that: list_items.indexOf('item-3')
https://codepen.io/marcelo-villela-gusm-o/pen/RwNEVVB?editors=1010
You can make a function to find the id you need in a list you want, passing two parameters, that way you can use this function dynamically.
Based on id, inside the function just need to use .findIndex() that returns the index or -1 if not found.
See here:
var list = document.getElementById('list');
var items = list.querySelectorAll('li:not([style*="display: none"])');
var list_items = Array.from(items);
function getIndexById(idToSearch, list){
//ES6 arrow function syntax
return list.findIndex(elem => elem.id == idToSearch)
//normal syntax
//return list.findIndex(function(elem) {return elem.id == idToSearch})
}
console.log("found at index: ", getIndexById("item-3", list_items))
<ul id="list">
<li id="item-1">1</li>
<li id="item-2" style="display: none">2</li>
<li id="item-3">3</li>
<li id="item-4">4</li>
<li id="item-5">5</li>
</ul>
Not exactly related to the question, but if possible, I would suggest you to change your HTML to remove that inline style of display: none and change it to a class, (e.g: class='hidden'), it would be better for your .querySelector when using :not, for example: li:not(.hidden), since any space in your inline style can break your selector. ("display:none" != "display: none", spot the space)
Maybe like this:
var item = list_items.find(function(item) {
return item.id === "item-3";
});
I would recommend using :not(.hidden) instead of "grepping" for a match on the style tag. Then, simply find the index after casting the NodeList to an array.
For the Vue.js inclined, see this fiddle: https://jsfiddle.net/634ojdq0/
let items = [...document.querySelectorAll('#list li:not(.hidden)')]
let index = items.findIndex(item => item.id == 'item-4')
console.log('item-4 index in visible list is', index)
.hidden {
display: none;
}
<ul id="list">
<li id="item-1">1</li>
<li id="item-2" class="hidden">2</li>
<li id="item-3">3</li>
<li id="item-4">4</li>
<li id="item-5">5</li>
</ul>
Maybe you can use map. First you can create an object with id and value. Then use map function to create array of this object. Then you can access it with foreach, when id = 'item-3'.
In angular 6 I want to access *ngFor last value as I want to operation if last value is set
eg
<li [ngClass]="list.mydata==1?'replies a':'sent a'" *ngFor="let list of chatlist; let last=last;">
<span [last]="last"></span>
<img src="{{list.profile_img}}" alt="" />
<div *ngIf="list.sender_type==0">
<p>{{list.message}}{{last}}</p>
</div>
<div *ngIf="list.sender_type==1">
<p style="background-color: burlywood;">{{list.message}}</p>
</div>
</li>
I want to do is [(myvar)]=last in place of let last=last
I want to bind the last variable so, I can access it is set or not in its component.
you can create a custom directive:
import { Directive, Output, EventEmitter, Input } from '#angular/core';
#Directive({
selector: '[onCreate]'
})
export class OnCreate {
#Output() onCreate: EventEmitter<any> = new EventEmitter<any>();
constructor() {}
ngOnInit() {
this.onCreate.emit('dummy');
}
}
and then you can use it in your *ngFor to call the method in your component:
<li [ngClass]="list.mydata==1?'replies a':'sent a'" *ngFor="let list of chatlist; let last=last;">
<span (onCreate)="onCreate(last)"></span>
<img src="{{list.profile_img}}" alt="" />
<div *ngIf="list.sender_type==0">
<p>{{list.message}}{{last}}</p>
</div>
<div *ngIf="list.sender_type==1">
<p style="background-color: burlywood;">{{list.message}}</p>
</div>
</li>
then in your component:
myvar: boolean = false;
onCreate(last) {
this.myvar = last;
}
checkout this DEMO.
Angular provides certain local variables when using *ngFor, one is for example last, which will (not as you expect currently) be a boolean value, being true if it is the last item. This is meant for adding specific stylings for the example to the last element of a list.
If you want that boolean you already use it correctly, but obviously the element using it should be a component. So instead of
<span [last]="last"></span>
it should be something like
<my-component [last]="last"></my-component>
where in my-component you define
#Input last: boolean;
and thus have access to it.
for example
<li [ngClass]="list.mydata==1?'replies a':'sent a'" *ngFor="let list of chatlist; let index=i;">
</li>
now you excess last elemnt like
<anyTag *ngIf="i === chatlist.length-1"></anyTag>