1161

What is wrong with my Angular code? I am getting the following error:

Cannot read property 'remove' of undefined at BrowserDomAdapter.removeClass

<ol>
  <li *ngClass="{active: step==='step1'}" (click)="step='step1'">Step1</li>
  <li *ngClass="{active: step==='step2'}" (click)="step='step2'">Step2</li>
  <li *ngClass="{active: step==='step3'}" (click)="step='step3'">Step3</li>
</ol>
BinaryButterfly
  • 18,137
  • 13
  • 50
  • 91
daniel
  • 34,281
  • 39
  • 104
  • 158

24 Answers24

2633

Angular version 2+ provides several ways to add classes conditionally:

type one

    [class.my_class] = "step === 'step1'"

type two

    [ngClass]="{'my_class': step === 'step1'}"

and multiple option:

    [ngClass]="{'my_class': step === 'step1', 'my_class2' : step === 'step2' }"

type three

    [ngClass]="{1 : 'my_class1', 2 : 'my_class2', 3 : 'my_class4'}[step]"

type four

    [ngClass]="step == 'step1' ? 'my_class1' : 'my_class2'"

You can find these examples on the documentation page

MiniClem
  • 20
  • 2
MostafaMashayekhi
  • 27,359
  • 3
  • 21
  • 39
  • 15
    Perfect answer, just fix the type 2 to: [ngClass]="{'my-class': step=='step1'}" With the '' int the class name – Adriano Galesso Alves Mar 28 '17 at 06:38
  • 4
    I was looking for the type four, but I'm wondering if I can add another class with another condition into that expression? Thanks in advance – Louay Hamada May 15 '18 at 17:48
  • 9
    For type three, the order of the class name and check is wrong. It should be class name first such as [ngClass]="{ 'my-class1': 1, 'my-class2': 2 }" – obaylis Jul 18 '18 at 11:33
  • 4
    looks like "type three" and "type four" are specific usages of `[ngClass]="js expression returning html class string"` so that are the same in this sense – YakovL Jul 26 '19 at 12:04
  • 1
    Looks like type four allows multiple classes also `[ngClass]="(step=='step1') ? 'my-class1 my-second-class1' : 'my-class2'"` – Jeppe Nov 08 '20 at 10:15
  • 2
    For type 4, in angular 10 i found that only the true case is applied, when false class attribute remain untouched (so in the example, my-class2 is not appended to original class attribute). – izio Nov 30 '20 at 07:43
  • 5
    Can anyone link me to the documentation for type one? I can't find it on angular website – featlorin Dec 17 '20 at 09:53
  • 1
    @MostafaMashayekhi can we apply multiple classes for the same condition? Is there a syntax for that? – Kitwradr Jan 11 '22 at 10:31
506

[ngClass]=... instead of *ngClass.

* is only for the shorthand syntax for structural directives where you can for example use

<div *ngFor="let item of items">{{item}}</div>

instead of the longer equivalent version

<template ngFor let-item [ngForOf]="items">
  <div>{{item}}</div>
</template>

See also https://angular.io/docs/ts/latest/api/common/index/NgClass-directive.html

<some-element [ngClass]="'first second'">...</some-element>
<some-element [ngClass]="['first', 'second']">...</some-element>
<some-element [ngClass]="{'first': true, 'second': true, 'third': false}">...</some-element>
<some-element [ngClass]="stringExp|arrayExp|objExp">...</some-element>
<some-element [ngClass]="{'class1 class2 class3' : true}">...</some-element>

See also https://angular.io/docs/ts/latest/guide/template-syntax.html

<!-- toggle the "special" class on/off with a property -->
<div [class.special]="isSpecial">The class binding is special</div>

<!-- binding to `class.special` trumps the class attribute -->
<div class="special"
     [class.special]="!isSpecial">This one is not so special</div>
<!-- reset/override all class names with a binding  -->
<div class="bad curly special"
     [class]="badCurly">Bad curly</div>
Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
  • 1
    From the angular documentation: "The asterisk is "syntactic sugar" for something a bit more complicated. Internally, Angular translates the *ngIf attribute into a element, wrapped around the host element, like this. The *ngIf directive moved to the element where it became a property binding,[ngIf]. The rest of the
    , including its class attribute, moved inside the element." - more info @ https://angular.io/guide/structural-directives#the-asterisk--prefix
    – Combine May 23 '19 at 08:56
  • Actually, it's nothing more complicated, `*` just allows a simplified synax instead of cannonical form. – Günter Zöchbauer Jun 28 '19 at 17:47
101

Another solution would be using [class.active].

Example :

<ol class="breadcrumb">
    <li [class.active]="step=='step1'" (click)="step='step1'">Step1</li>
</ol>
Joel Almeida
  • 7,939
  • 5
  • 25
  • 51
95

That's the normal structure for ngClass is:

[ngClass]="{'classname' : condition}"

So in your case, just use it like this...

<ol class="breadcrumb">
  <li [ngClass]="{'active': step==='step1'}" (click)="step='step1'">Step1</li>
  <li [ngClass]="{'active': step==='step2'}" (click)="step='step2'">Step2</li>
  <li [ngClass]="{'active': step==='step3'}" (click)="step='step3'">Step3</li>
</ol>
Sunil Garg
  • 14,608
  • 25
  • 132
  • 189
Alireza
  • 100,211
  • 27
  • 269
  • 172
83

with the following examples you can use 'IF ELSE'

<p class="{{condition ? 'checkedClass' : 'uncheckedClass'}}">
<p [ngClass]="condition ? 'checkedClass' : 'uncheckedClass'">
<p [ngClass]="[condition ? 'checkedClass' : 'uncheckedClass']">
53

You can use ngClass to apply the class name both conditionally and not in Angular

For Example

[ngClass]="'someClass'">

Conditional

[ngClass]="{'someClass': property1.isValid}">

Multiple Condition

 [ngClass]="{'someClass': property1.isValid && property2.isValid}">

Method expression

[ngClass]="getSomeClass()"

This method will inside of your component

 getSomeClass(){
        const isValid=this.property1 && this.property2;
        return {someClass1:isValid , someClass2:isValid};
    }
jmcgrath207
  • 1,317
  • 2
  • 19
  • 31
Jameel Moideen
  • 7,542
  • 12
  • 51
  • 79
  • 1
    Hello, sorry, I'm a bit new to angular. Is using [ngClass]="getSomeClass()" considered a good practice? From what I can see in logs - it gets evaluated every few milliseconds. Thanks in advance – Jack Feb 02 '22 at 10:13
  • @Jack It's depends , if you want to perform some additional business logic to apply the class , method will make more sense. Writing those logic on the html is tedious. – Jameel Moideen Feb 05 '22 at 23:09
48

Angular provides multiple ways to add classes conditionally:

First way

active is your class name

[class.active]="step === 'step1'"

Second way

active is your class name

[ngClass]="{'active': step=='step1'}"

Third way

by using ternary operator class1 and class2 is your class name

[ngClass]="(step=='step1')?'class1':'class2'"
Mironline
  • 2,755
  • 7
  • 35
  • 61
Naeem Bashir
  • 1,937
  • 20
  • 17
21

You should use something ([ngClass] instead of *ngClass) like that:

<ol class="breadcrumb">
  <li [ngClass]="{active: step==='step1'}" (click)="step='step1; '">Step1</li>
  (...)

Thierry Templier
  • 198,364
  • 44
  • 396
  • 360
19

In Angular 7.X

The CSS classes are updated as follows, depending on the type of the expression evaluation:

  • string - the CSS classes listed in the string (space delimited) are added

  • Array - the CSS classes declared as Array elements are added

  • Object - keys are CSS classes that get added when the expression given in the value evaluates to a truthy value, otherwise they are removed.

<some-element [ngClass]="'first second'">...</some-element>

<some-element [ngClass]="['first', 'second']">...</some-element>

<some-element [ngClass]="{'first': true, 'second': true, 'third': false}">...</some-element>

<some-element [ngClass]="stringExp|arrayExp|objExp">...</some-element>

<some-element [ngClass]="{'class1 class2 class3' : true}">...</some-element>
span
  • 5,405
  • 9
  • 57
  • 115
Rohit.007
  • 3,414
  • 2
  • 21
  • 33
15

Additionally, you can add with method function:

In HTML

<div [ngClass]="setClasses()">...</div>

In component.ts

// Set Dynamic Classes
  setClasses() {
    let classes = {
      constantClass: true,
      'conditional-class': this.item.id === 1
    }

    return classes;
  }
Alper BULUT
  • 284
  • 2
  • 8
10

to extend MostafaMashayekhi his answer for option two> you can also chain multiple options with a ','

[ngClass]="{'my-class': step=='step1', 'my-class2':step=='step2' }"

Also *ngIf can be used in some of these situations usually combined with a *ngFor

class="mats p" *ngIf="mat=='painted'"
9

You can use [ngClass] or [class.classname], both will work the same.
[class.my-class]="step==='step1'"

   OR

[ngClass]="{'my-class': step=='step1'}"

Both will work the same!

Waleed Shahzaib
  • 1,526
  • 2
  • 18
  • 34
8

While I was creating a reactive form, I had to assign 2 types of class on the button. This is how I did it:

<button type="submit" class="btn" [ngClass]="(formGroup.valid)?'btn-info':''" 
[disabled]="!formGroup.valid">Sign in</button>

When the form is valid, button has btn and btn-class (from bootstrap), otherwise just btn class.

Sarvar Nishonboyev
  • 12,262
  • 10
  • 69
  • 70
7

We can make class dynamic by using following syntax. In Angular 2 plus, you can do this in various ways:

[ngClass]="{'active': arrayData.length && arrayData[0]?.booleanProperty}"
[ngClass]="{'active': step}"
[ngClass]="step== 'step1'?'active':''"
[ngClass]="step? 'active' : ''"
fcdt
  • 2,371
  • 5
  • 14
  • 26
Sunny
  • 1,286
  • 12
  • 16
6

Let, YourCondition is your condition or a boolean property, then do like this

[class.yourClass]="YourCondition"
Abdus Salam Azad
  • 5,087
  • 46
  • 35
5

The directive operates in three different ways, depending on which of three types the expression evaluates to:

  1. If the expression evaluates to a string, the string should be one or more space-delimited class names.
  2. If the expression evaluates to an object, then for each key-value pair of the object with a truthy value the corresponding key is used as a class name.
  3. If the expression evaluates to an array, each element of the array should either be a string as in type 1 or an object as in type 2. This means that you can mix strings and objects together in an array to give you more control over what CSS classes appear. See the code below for an example of this.
    [class.class_one] = "step === 'step1'"

    [ngClass]="{'class_one': step === 'step1'}"

For multiple options:

    [ngClass]="{'class_one': step === 'step1', 'class_two' : step === 'step2' }" 

    [ngClass]="{1 : 'class_one', 2 : 'class_two', 3 : 'class_three'}[step]"

    [ngClass]="step == 'step1' ? 'class_one' : 'class_two'"
Tharindu Lakshan
  • 3,995
  • 6
  • 24
  • 44
4

This is what worked for me:

[ngClass]="{'active': dashboardComponent.selected_menu == 'profile'}"
Prashant Pimpale
  • 10,349
  • 9
  • 44
  • 84
Ninad Kulkarni
  • 474
  • 4
  • 7
4

ngClass syntax:

[ngClass]="{'classname' : conditionFlag}"

You can use like this:

<ol class="breadcrumb">
  <li [ngClass]="{'active': step==='step1'}" (click)="step='step1'">Step1</li>
  <li [ngClass]="{'active': step==='step2'}" (click)="step='step2'">Step2</li>
  <li [ngClass]="{'active': step==='step3'}" (click)="step='step3'">Step3</li>
</ol>
Chirag
  • 413
  • 1
  • 6
  • 16
3

For elseif statement (less comparison) use like that: (For example you compare three statement)

<div [ngClass]="step === 'step1' ? 'class1' : (step === 'step2' ? 'class2' : 'class3')"> {{step}} </div>
2

Not relevant with [ngClass] directive but I was also getting the same error as

Cannot read property 'remove' of undefined at...

and I thought to be the error in my [ngClass] condition but it turned out the property I was trying to access in the condition of [ngClass] was not initialized.

Like I had this in my typescript file

element: {type: string};

and In my [ngClass] I was using

[ngClass]="{'active', element.type === 'active'}"

and I was getting the error

Cannot read property 'type' of undefined at...

and the solution was to fix my property to

element: {type: string} = {type: 'active'};

Hope it helps somebody who is trying to match a condition of a property in [ngClass]

Hamza Khanzada
  • 1,439
  • 1
  • 22
  • 39
1

<div class="collapse in " [ngClass]="(active_tab=='assignservice' || active_tab=='manage')?'show':''" id="collapseExampleOrganization" aria-expanded="true" style="">
 <ul>   <li class="nav-item" [ngClass]="{'active': active_tab=='manage'}">
<a routerLink="/main/organization/manage" (click)="activemenu('manage')"> <i class="la la-building-o"></i>
<p>Manage</p></a></li> 
<li class="nav-item" [ngClass]="{'active': active_tab=='assignservice'}"><a routerLink="/main/organization/assignservice" (click)="activemenu('assignservice')"><i class="la la-user"></i><p>Add organization</p></a></li>
</ul></div>

Code is good example of ngClass if else condition.

[ngClass]="(active_tab=='assignservice' || active_tab=='manage')?'show':''"

[ngClass]="{'active': active_tab=='assignservice'}"
amarbhanu
  • 9
  • 2
1

Try Like this..

Define your class with ''

<ol class="breadcrumb">
    <li *ngClass="{'active': step==='step1'}" (click)="step='step1; '">Step1</li>
    <li *ngClass="{'active': step==='step2'}"  (click)="step='step2'">Step2</li>
    <li *ngClass="{'active': step==='step3'}" (click)="step='step3'">Step3</li>
</ol>
0

If user want to display the class on basis of && and || then below one is work for me

[ngClass]="{'clasname_1':  condition_1 && condition_2, 'classname_2':  condition_1 && condition2, 'classname_3': condition}"

Example:

[ngClass]="{'approval-panel-mat-drawer-side-left':  similar_toil_mode==='side' && showsTheSimilarToilsWithCloseIcon, 'approval-panel-mat-drawer-side-right':  similar_toil_mode==='side' && !showsTheSimilarToilsWithCloseIcon, 'approval-panel-mat-drawer-over': similar_toil_mode==='over'}"
Priyanka Ahire
  • 432
  • 2
  • 9
  • 28
0

The example is a bit big, but triggering a class instead of typing inline is my first preferred approach. this way you can add as many possibilities as you want to your element. There may be a way for those who want to bind more than one [ngClass] to a single element.

<span class="inline-flex items-center font-medium" [ngClass]="addClass">{{ badge.text }}</span>

import { ChangeDetectionStrategy, Component, Input } from '@angular/core';

type Badge = {
    size?: 'basic' | 'large';
    shape?: 'basic' | 'rounded';
    color?: 'gray' | 'red' | 'yellow' | 'green' | 'blue' | 'indigo' | 'purple' | 'pink';
    dot?: boolean;
    removeButton?: false;
    text?: string;
}

@Component({
    selector: 'bio-badge',
    templateUrl: './badge.component.html',
    styleUrls: ['./badge.component.scss'],
    changeDetection: ChangeDetectionStrategy.OnPush,
})
export class BioBadgeComponent {
    @Input() badge!: Badge;
    get addClass() {
        return {
            'px-2.5 py-0.5 text-sx': this.badge.size === 'basic',
            'px-3 py-0.5 text-sm': this.badge.size === 'large',
            'rounded-full': this.badge.shape === 'basic',
            'rounded': this.badge.shape === 'rounded',
            'bg-gray-100 text-gray-800': this.badge.color === 'gray',
            'bg-red-100 text-red-800': this.badge.color === 'red',
            'bg-yellow-100 text-yellow-800': this.badge.color === 'yellow',
            'bg-green-100 text-green-800': this.badge.color === 'green',
            'bg-blue-100 text-blue-800': this.badge.color === 'blue',
            'bg-indigo-100 text-indigo-800': this.badge.color === 'indigo',
            'bg-purple-100 text-purple-800': this.badge.color === 'purple',
            'bg-pink-100 text-pink-800': this.badge.color === 'pink',
        }
    }
}

umutyerebakmaz
  • 887
  • 8
  • 18