How to setup the class in my case - html

I am trying to add the class by ng-class in my app.
I have something like
html
<li ng-repeat="item in items"
ng-click="getItem(item)"
ng-class="{shine : item.isPick}" // shine class will make the font color change to red
>{{item.name}}
</li>
In my controller
$scope.getItem = function(item) {
$scope.items.forEach(function(item){
item.isPick = false; // remove all the items that have shine class
})
item.isPick = true; // adding the shine class back
}
Basically I want to remove every other 'shine' class except the selected item when user clicks it. My codes above work but I am thinking there is a better way to do it instead of looping all the items. Can someone help me about it? Thanks a lot!

Use the $index in the repeater, and add the class when that index is selected:
<li ng-repeat="item in items"
ng-click="getItem($index)"
ng-class="{shine : activeIndex == $index}"
>{{item.name}}
</li>
$scope.getItem = function(index) {
$scope.activeIndex = index;
}

Related

How to hide a component if there is no result found in Angular

In my Home page, I have a search bar and imported three components. my search bar have the ability to search through them but just wondering how can I hide a particular component if a result in not found in that component and only show a component that have a result.
The problem I have right now is, if search result is only found in Application group component then, the attachment and training component is showing me blank (pls check uploaded image below). I just want to hide the components that don't have the result while user is filtering/searching and just show it back the component when a user cancel the search.
I would be really appreciated if I can get help or suggestion on this.
<!-- attachments -->
<div>
<app-attachment [attachments]="entity.attachments"></app-attachment>
</div>
<!-- appgroups -->
<div *ngFor="let entityGroup of entity.entityGroups">
<app-application-group [entityGroup]="entityGroup" [entity]="entity"></app-application-group>
</div>
<!-- Training and Support -->
<div>
<app-training [entity]="entity"></app-training>
</div>
</div>
ngOnInit(): void {
this.searchText$ = this.searchService.searchText
.asObservable()
.pipe(debounceTime(750), distinctUntilChanged())
.subscribe((value) => {
this.filterValue = value;
this.loadApplication(this.entityType, this.entityId);
});
this.collapse = false;
this.expanded = true;
this.route.url.subscribe((_value) => {
this.entityType = BaseEntity.stringToType(_value[0].path);
this.entityId = Number(_value[1].path);
this.loadApplication(this.entityType, this.entityId);
this.populateMeetups(this.entityId);
});
}
loadApplication(entityType: EntityType, entityId: number): void {
this.color = BaseEntity.color(this.entityType);
if (this.entityType && this.entityId) {
// this.filterValue = null;
this.childrenActive = null;
this.pageSize = 999;
this.childrenActive = true; // We want to bring only active children for things that have tables.
}
this.entityService
.getApplicationDetails(
entityId,
entityType,
this.pageSize,
this.childrenActive,
this.filterValue,
)
.subscribe((entity) => {
this.entity = entity;
this.ancestor = this.entity.channels.get(0);
this.entityGroup = this.entity.entityGroups.filter(
(r) => r.entityType === EntityType.Application,
);
this.entity.attachments = this.entity.attachments.filter((app) => {
return app.name.toLowerCase().includes(this.filterValue.toLowerCase());
});
});
}
click here to view my screenshot
Use *ngIf to remove stuff from the DOM you don't want to show. For example:
<ng-container *ngIf="entity.attachments?.length">
<div>
<app-attachment [attachments]="entity.attachments"></app-attachment>
</div>
</ng-container>
Or hide it with css:
<div [ngClass]="entity.attachments?.length ? 'show' : 'hide'">
<app-attachment [attachments]="entity.attachments"></app-attachment>
</div>
and the css:
.hide {
visibility: hidden;
}
You may want to consider placing the *ngIf inside the child component instead of the parent.
Try to use ngIf by checking the length of the search result instead of creating a new variable. Also use else block to display no result found as shown below
Show result here
No result found .

How to use class with class conditional

I am trying to use both regular class attribute and class conditional attribute in an html element below:
<ul *ngIf="showDropdown">
<li class="active" [class.active]="sIndex === x" (click)="dropdownSelect($event.target.value, x)" value="18203">All Groceries</li>
<li [class.active]="sIndex === x" (click)="dropdownSelect($event.target.value, x)" *ngFor='let i of lists; let x = index' value="{{i.id}}">{{i.name}}</li>
</ul>
I have the first li I want to be active but have click attribute which toggles click. Any ideas?
You can use
[ngClass]={"active": sIndex === x}
But in your code you already have the class "active" by default, so nothing will change, always going to have the active class.
explain more, what you want to do.
You're example is looking weird ,
the first li is always active no matter what will happen , and both of li have the same condition that makes them active .
Try this
<ul *ngIf="showDropdown">
<li [class.active]="sIndex === x" (click)="dropdownSelect($event.target.value, x)" value="18203">All Groceries</li>
<li [class.active]="sIndex !== x" (click)="dropdownSelect($event.target.value, x)" *ngFor='let i of lists; let x = index' value="{{i.id}}">{{i.name}}</li>
</ul>
This is the right way to add a class in case its true
[class.active]="sIndex === x"
I figured the answer out. So if you want to have a conditional where active class changes when you click, but want an active class on any element first you do the following:
[ngClass]="{'active': sIndex === x || first}" (click)="dropdownSelect($event.target.value, x)"
add a conditional parameter with your toggle active class on click.
constructor(private api: API, private http: Http) {
this.first = true;
}
you set first to true in in your constructor. then when someone clicks, you put it into function and set it to false;
dropdownSelect(v, x: number) {
this.filter = v;
this.sIndex = x;
this.showDropdown = !this.showDropdown;
this.first = false;
}

Add and Remove class in Angular

I want to add background color to the li element when clicked but when I clicked another li element the previous li element background color remains unchanged.
component.html
<div class="col-md-3 categories">
<h3>News By Type</h3>
<ul>
<li class="cat" id="cat_{{i}}" *ngFor="let category of categories; let i = index" (click)="sortNewsItems($event,category,i)"><img src="../assets/images/news.jpg" width="70"><h4>{{category}}</h4></li>
</ul>
</div>
component.ts
sortNewsItems(event,cat,index) {
event.target.classList.add('cat_active');
}
You should use srcElement of the $event
sortNewsItems(event,cat,index) {
event.srcElement.classList.add('cat_active');
}
Read this answer and use its demo
I know this is an old post but just in case. when there are several classes already on the element you might just want to add or remove an extra class you can do this:
On the element:
<div #element </div>
On the component.ts
#ViewChild('element') element: ElementRef;
then you can just add classes or remove them by
this.element.nativeElement.classList.add("newclass");
this.element.nativeElement.classList.remove("newclass");
Remove 'cat_active' class from all the sibling elements before adding a new 'cat_active' class to the selected element.
component.html
<li #li class="cat" *ngFor="let category of categories;" (click)="sortNewsItems($event)">
component.ts
#ViewChildren('li') livs: QueryList<any>;
constructor(private elementRef: ElementRef) { }
sortNewsItems(event) {
this.livs.forEach(liv => liv.nativeElement.children[0].classList = []);
event.target.classList.add('cat_active');
}
I hope it might helps.
Use ngStyle instead of direct class binding in html element.
component.html
<div class="col-md-3 categories">
<h3>News By Type</h3>
<ul>
<li [ngStyle]="setListItemStyle(category)" class="cat" id="cat_{{i}}" *ngFor="let category of categories; let i = index" (click)="sortNewsItems($event,category,i)"><img src="../assets/images/news.jpg" width="70"><h4>{{category.label}}</h4></li>
</ul>
</div>
component.ts
activeListItem: any = null;
categories: any[] = [{ id: 1, label: 'Test label 1' }, { id: 2, label: 'Test label 2' }];
sortNewsItems(event, category, i) {
event.stopPropagation();
this.activeListItem = category;
}
setListItemStyle(category) {
return { 'background-color': this.activeListItem && this.activeListItem.id == category.id ? '#fff000' : null };
}
I just taken a variable and set category name to it when clicked on category li and add active class based on the below condition. finally I set it like what i want. Thank you everyone for the well support.
component.html
<li class="cat" *ngFor="let category of categories; let i = index" (click)="sortNewsItems(category,i)" [ngClass]="{'cat_active':toggleClass === category}"><img src="../assets/images/news.jpg" width="70"><h4>{{category}}</h4></li>
component.ts
toggleClass:string;
sortNewsItems(cat,index) {
this.toggleClass = cat;
}
I read that using srcElement is not a "so good" practice. Better to use renderer2.
<any-element [ngClass]="{selected: isSelected}">
...
</any-element>
OR
<any-element [ngClass]="{selected: isSelected, disabled: isDisabled}">
...
</any-element>
document.querySelector(".menu-open-btn a").onclick = function addNewClass() {
document.querySelector(".mobile-header").classList.add("newClass");
}

change <li> style by click

I am using Angular CLI. Actually, I have a menu list. And I would like to change the background color of <li> when I click on it.
I send id to functionchangeColor(). But the problem is I am getting menuButton as null. Please help me to do so.
.html
<ul>
<li id="menu_btn" (click)="changeColor()" >
</li>
<li id="menu_btn" (click)="changeColor()">
</li>
<ul>
.ts:
changeColor() {
let menuButton = document.getElementById("menu_btn");
menuButton.style.backgroundColor = '#816587';
}
The more angular way to do this is define your menu list in an array
// component.ts
menuList = [
{
name: 'Option 1',
isSelected: false
},
{
name: 'Option 2',
isSelected: false
}
];
Then use an ngFor to render the list and use ngClass + each menu items isSelected flag to toggle a selected class.
// component.html
<ul>
<li *ngFor="let menuItem of menuList" (click)="changeColor(menuItem)"
[ngClass]="{'selected': menuItem.isSelected}">
{{menuItem.name}}
</li>
</ul>
// component.css
.selected{
background-color: #816587;
}
Now have your changeColor method handle the toggling of the isSelected flag
changeColor(menuItem){
// toggle off all selected menu items
this.menuList.forEach(item => {
if(item.isSelected){
item.isSelected = false;
}
});
// select clicked menu item
menuItem.isSelected = true;
}
This way angular is handling all of the DOM manipulation. Here is plnkr demonstrating this functionality (https://plnkr.co/edit/NEnzKZ84M85mErYGLE1Y?p=preview)
You can use ngStyle to do this:
<li id="menu_btn" (click)="myStyle = {'background-color': #816587}" [ngStyle]="myStyle">

Knockout data-bind css if function

I want to add a class to an element if the title of the page includes "Home".
Currently, I use this:
<li data-bind="css: { 'active': function(){return document.title.indexOf('Home') > -1;}}">
However this does not work, this function does not get executed...
How do I make this work?
Knockout wraps the value in a computed function in a way that resembles this:
Input: "yourClassName": whateverYouPutIn
Output: "yourClassName": ko.computed(function() { return whateverYouPutIn; })
In your case, you put in a function, which will result in a "truethy" value setting the active class. You can fix this by:
Option 1 (quick): Don't wrap it in a function
<li data-bind="css: {
'active': document.title.indexOf('Home') > -1
}"></li>
Option 2 (not recommended): Fix the typo (funciton) and call the function
<li data-bind="css: {
'active': (function() {
return document.title.indexOf('Home') > -1;
}())
}"></li>
Option 3: Add these kinds of properties to your viewmodel
var vm = {
// set when VM is initialized
isActive: document.title.indexOf("Home"),
// if you want to check the title during data-binding
isActiveDuringBind: function() {
return document.title.indexOf("Home");
}
}
With either
<li data-bind="css: {'active': isActive }"></li>
or
<li data-bind="css: {'active': isActiveDuringBind() }"></li>
Note that using the DOM api outside of custom bindings is considered "bad practice"... But in this case I guess you can get away with it...
Note that because there are no observable values being used, your class will not toggle when you change document.title.