26

I have list items as follows in below code snippet. On mouse click I would like to select that item (add 'active' class and deselect if any other items (siblings) selected by remove'active class. I have achieved the same using jQuery (full code below). How I can achieve the functionality in Angular 2 way.

Code snippet:

<!DOCTYPE html>
<html>
<head>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
</head>
<body>
<ul id="grouplist" class="list-group">
    <li class="list-group-item">Item1</li>
    <li class="list-group-item">Item2</li>
    <li class="list-group-item">Item3</li>
    <li class="list-group-item">Item4</li>
    <li class="list-group-item">Item5</li>
    <li class="list-group-item">Item6</li>
    <li class="list-group-item">Item7</li>
    <li class="list-group-item">Item8</li>
    <li class="list-group-item">Item9</li>
    <li class="list-group-item">Item10</li>
</ul>
<script>
$(function () {
    $('.list-group li').click(function() {
        $(this).addClass('active').siblings().removeClass('active');
    });
})
</script>
</body>
</html>

JSFiddle here

Angular 2 Experiment: I am able to set class via 'setElementClass'. How to remove 'active' class from siblings? Or is there any other approaches?

List view component (test1.component.html):

<h2>Select List Item</h2>

<ul id="grouplist" class="list-group">
    <li class="list-group-item" (click)="listClick($event)" *ngFor="let item of groups">
        {{ item.name }}
    </li>
</ul>

TypeScript Code (test1.component.ts):

import { Component } from '@angular/core';
import { Renderer } from '@angular/core';
import { Group } from './group';

@Component({
    selector: 'test1',
    template: require('./test1.component.html')
})
export class Test1Component {

    groups: Group[];

    constructor(private render: Renderer) {
        this.groups = [new Group("item1"), new Group("item2"), new Group("item3"), new Group("item4"), new Group("item5")];
    }

    public listClick(event: any) {
        event.preventDefault();
        this.render.setElementClass(event.target, "active", true);
        // How to remove 'active' from siblings ?
    }
}

group.ts

export class Group {
    constructor(public name: String) {
    }
}
RK_Aus
  • 886
  • 1
  • 11
  • 18
  • 1
    Angular 2 or Angular 1 ? It would be good to see what you've done so far, so we can improve/correct it. This seems to be just asking us for the complete answer. – Searching Dec 06 '16 at 02:08
  • Angular 2 - Updated my question with my Angular 2 code. – RK_Aus Dec 06 '16 at 02:48

4 Answers4

56

You can use ngClass for what you are looking for:

 <ul id="grouplist" class="list-group">
     <li class="list-group-item" [ngClass]="{'active': selectedItem == item}" (click)="listClick($event, item)" *ngFor="let item of groups">
        {{ item.name }}
     </li>
</ul>

And in your listClick just set the selected item to that item:

listClick(event, newValue) {
    console.log(newValue);
    this.selectedItem = newValue;  // don't forget to update the model here
    // ... do other stuff here ...
}
Yaser
  • 5,609
  • 1
  • 15
  • 27
  • Thank you, Yaser. In the given code (listClick()), please let me know how to set the selected item. Sorry if it is a basic question, I am quite new to Angular 2. – RK_Aus Dec 06 '16 at 05:15
  • if i update the model object inside the click handler, how will i able to refresh the template html. – Karan Jun 05 '18 at 12:35
  • @Karan if by updating the model you mean `item` then either you need to fire an event or trigger the change detection manually – Yaser Jun 05 '18 at 13:03
  • @Yaser I've got a similar case. what if it should be used for chat list and each chat list item has (click)="GoToChatPage(chat.receiverId.username)" and opens messages on the right for that selected chat list user with you? I've posted a question here: https://stackoverflow.com/questions/53691060/how-to-add-active-class-on-selected-chat-list-item-angular How can I refactor this code to fit for my issue? –  Dec 09 '18 at 11:44
  • @Artur answered your question – Yaser Dec 09 '18 at 21:41
  • what happen if user reload the page? I think the selection will go. Can you have solution for that? – user3723041 Dec 20 '19 at 05:26
  • In that case you need to store the selection in the local storage and retrieve it on load, then assign it to your local variable to get the job done. Have a look at this answer for example: https://stackoverflow.com/questions/51536262/angular-6-saving-data-to-local-storage – Yaser Jan 06 '20 at 00:54
  • How to active first li starting? – Pappa S Jun 28 '20 at 18:08
21

You can also just pass the index of the li element to your component during a click event:

<ul id="grouplist" class="list-group">
   <li *ngFor="let item of items; let i=index" (click)="select(i)" 
       [ngClass]="{'active': selectedIndex == i, 'list-group-item': true}" >
      {{ item.text }}
   </li>
</ul>

Then let you component set its selectedIndexproperty:

@Component({
  ...
})
export class ItemListComponent {
  ...
  selectedIndex: number;
  select(index: number) {
      this.selectedIndex = index;
  }
}

The selectedIndexis used by the template to determine whether to assign the active class to the li element.

See it in this Plunker

Frank Fajardo
  • 7,034
  • 1
  • 29
  • 47
  • 1
    Hi Frank, thank you for the answer. This one also works as expected. Since Yaser give the answer first, accepted that answer. Sorry, I'm able to select only one answer. – RK_Aus Dec 06 '16 at 21:31
  • @Frank. Sir can you please answer my question: https://stackoverflow.com/questions/59154020/how-to-apply-css-dynamically-on-selected-items-only-angular?noredirect=1#comment104533181_59154020 – Tanzeel Dec 03 '19 at 10:33
  • 1
    @Frank Fajardo this is the simpliest solution I ever had – kushal Baldev Oct 04 '20 at 12:39
0

For those who aren't convinced with the accepted solution and coming from an AngularJS background, here's a solution for you.

HTML:

<li *ngFor="let quality of qualities" 
    [ngClass]="quality.id === activeElement ? 'active' : 'none'"
    (click)="selectedItem(quality.id)"
    >
  {{quality.quality}}
</li>

CSS:

.active {
  background-color: #000000;
  color : #ffffff;
}

Component:

public activeElement = 1;  
public selectedItem(id) {
    this.activeElement = id;
 }

Note : My ngFor's collection is like qlist = [ { quality: 'About Me', id: 1 }] So, I'm using quality.id to switch the class, you can use your own attribute to switch. Just change the activeElement variable to whatever you want to make it default.

sagars01
  • 356
  • 1
  • 9
0

<ul id="grouplist" class="list-group">
     <li class="list-group-item" [ngClass]="{'active': selectedItem == item}" 
     (click)="listClick($event, item)" *ngFor="let item of groups">
        {{ item.name }}
     </li>
    </ul>
listClick(event, newValue) {
     console.log(newValue);
     this.selectedItem = newValue;  // don't forget to update the model here
     // ... do other stuff here ...
    }

To apply active class on click of selected item & remove it from another element click

onClickOfOtherElement(){
  this.selectedItem = ''
}
Bhavi P
  • 1
  • 4