31

We're using bootstrap, and sometimes it automatically adds classes to DOM elements. What is the best way to attach to these elements and detect when a particalr css class is added to a component template child element?

Say i have this component:

import { Component, ViewChild, ElementRef } from '@angular/core';
import { HeaderService } from './header.service';

@Component({
    selector: 'header-comp',
    templateUrl: './Home/RenderLayoutHeader'
})

export class HeaderLayoutComponent {
    constructor(private _headerService: HeaderService) { }
}

And this is a portion of my view template:

<header-comp>      
<li class="nav-header-icon-list-item">
                        <div class="overlay-dropdown dropdown" id="patientDDL">
                            <button  class="btn btn-default dropdown-toggle session-menu-container" type="button" id="session-dropdown-menu" data-toggle="dropdown" data-backdrop="true" data-dismiss="modal"  aria-haspopup="true" aria-expanded="false">
                                <img data-initials="ER" src="https://lorempixel.com/40/40/abstract/" class="img-circle session-user-profile-img">

How do i detect in my component when bootstrap adds "open" class to #patientDDL element and execute a function in my component?

Thanks!

EDIT: I modified my component to this per Gunter's solution but I'm getting a null reference when i don't precede the criteria with a null check)

import { Component, ViewChild, ElementRef, DoCheck } from '@angular/core';
import { HeaderService } from './header.service';

@Component({
    selector: 'header-comp',
    templateUrl: './Home/RenderLayoutHeader'
})

export class HeaderLayoutComponent implements DoCheck {

    @ViewChild('patientDDL') patientDropDownList: ElementRef;

    constructor(private _headerService: HeaderService) { }

    ngDoCheck() {
        console.log('ngDoCheck called');
        if (this.patientDropDownList && this.patientDropDownList.nativeElement.classList.contains('open')) {
            this._headerService.setPatientDDLOpen(true);
        } else {
            this._headerService.setPatientDDLOpen(false);
        }

    }
}

Also the console statment is logged 4 times while the template loads but then it is never invoked again, even after the class has been added/removed multiple times.

This is angular2 rc1 not sure if that is relevant.

1 Answer 1

57

Add a template variable to be able to query the element.

<div #patientDDL class="overlay-dropdown dropdown" id="patientDDL">

Query the element

@ViewChild('patientDDL') patientDDL:ElementRef;

Implement ngDoCheck() to run the check whether the class was added when change detection runs:

ngDoCheck() {
  if(patientDDL.nativeElement.classList.contains('open')) {
    this.doSomething();
  }
} 

or on some specific event

@HostListener('click', ['$event'])
clickHandler(event) {
  if(patientDDL.nativeElement.classList.contains('open')) {
    this.doSomething();
  }
} 
Sign up to request clarification or add additional context in comments.

6 Comments

I was just thinking can't you do anything using @HostBinding?
You can set and remove a class but Angular2 doesn't provide anything to read from DOM elements.
when does ngDoCheck fire? I ask because it doesn't seem to be firing when the element is clicked and the class is added.
@GünterZöchbauer is foobar.nativeElement.classList.contains('open') a good practice or is there another way to do that (using the renderer or anything else)? Thanks :)
@sebaferreras renderer (or Angular in general) doesn't provide anything about reading from the DOM. If you need to read from the DOM, direct DOM access is the only way. In a pure Angular application reading classList should never be necessary though. There are some things where direct DOM access can't be avoided though, even in pure Angular applications.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.