daniel
daniel

Reputation: 35733

Angular: conditional class with *ngClass

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>

Upvotes: 1239

Views: 2275674

Answers (25)

MostafaMashayekhi
MostafaMashayekhi

Reputation: 29009

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 options:

[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 the documentation page.

Upvotes: 2796

OMANSAK
OMANSAK

Reputation: 1332

Some usefull helper pipes for ngClass

@Pipe({
    name: 'condition'
})
export class ONgConditionPipe implements PipeTransform {
    transform(value: any, condition?: any): any {
        if (condition != null) {
            return value;
        }

        if (value) {
            return value;
        }
    }
}

@Pipe({
    name: 'default'
})
export class ONgDefaultPipe implements PipeTransform {
    transform(value: any, defaultValue?: any): any {
        return value ?? defaultValue;
    }
}

Example

[ngClass]="[headerClass | default: '', 'cursor-move' | condition: draggable, ('cursor-move2' | condition: draggable) | default: '']"

Upvotes: 0

Alper Bulut
Alper Bulut

Reputation: 314

Additionally, you can assign a value returned by a 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;
  }

Upvotes: 18

umutyerebakmaz
umutyerebakmaz

Reputation: 1037

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',
        }
    }
}

Upvotes: 2

Priyanka Ahire
Priyanka Ahire

Reputation: 502

If a user wants to display the class on basis of && and ||, then the below one is working 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'}"

Upvotes: 0

Try it 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>

Upvotes: 1

Chirag
Chirag

Reputation: 413

ngClass syntax:

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

You can 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>

Upvotes: 4

Rohit.007
Rohit.007

Reputation: 3502

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>

Upvotes: 19

Chaitanya Nekkalapudi
Chaitanya Nekkalapudi

Reputation: 1077

With the following examples, you can use 'IF ELSE':

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

Upvotes: 86

Halil Oymacı
Halil Oymacı

Reputation: 867

For an elseif statement (less comparison), use it like this (for example, you compare three statements):

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

Upvotes: 3

Sunny
Sunny

Reputation: 1476

We can make a class dynamic by using the 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' : ''"

Upvotes: 8

amarbhanu
amarbhanu

Reputation: 9

Use:

<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>

The code is a good example of an ngClass if-else condition.

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

[ngClass]="{'active': active_tab=='assignservice'}"

Upvotes: 1

Hamza Khanzada
Hamza Khanzada

Reputation: 1525

It is not relevant with the [ngClass] directive, but I was also getting the same error as

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

and I thought it 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'};

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

Upvotes: 2

Abdus Salam Azad
Abdus Salam Azad

Reputation: 5492

Let YourCondition be your condition or a Boolean property. Then do it like this:

[class.yourClass]="YourCondition"

Upvotes: 9

Robert Leeuwerink
Robert Leeuwerink

Reputation: 489

To extend MostafaMashayekhi's 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'"

Upvotes: 10

Alireza
Alireza

Reputation: 104870

That's the normal structure. For ngClass, it 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>

Upvotes: 96

G&#252;nter Z&#246;chbauer
G&#252;nter Z&#246;chbauer

Reputation: 657937

[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 NgClass.

<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 Template syntax

<!-- 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>

Upvotes: 523

Joel Almeida
Joel Almeida

Reputation: 8047

Another solution would be using [class.active].

Example:

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

Upvotes: 102

Thierry Templier
Thierry Templier

Reputation: 202286

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

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

Upvotes: 21

Naeem Bashir
Naeem Bashir

Reputation: 2017

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'"

Upvotes: 51

Tharindu Lakshan
Tharindu Lakshan

Reputation: 6196

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'"

Upvotes: 5

Waleed Shahzaib
Waleed Shahzaib

Reputation: 1716

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!

Upvotes: 9

Ninad Kulkarni
Ninad Kulkarni

Reputation: 476

This is what worked for me:

[ngClass]="{'active': dashboardComponent.selected_menu == 'profile'}"

Upvotes: 4

Jameel Moideen
Jameel Moideen

Reputation: 7941

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};
    }

Upvotes: 56

Sarvar Nishonboyev
Sarvar Nishonboyev

Reputation: 13110

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.

Upvotes: 8

Related Questions