Trigger event when element becomes visible with ngIf

20,197

Solution 1

This can be a possible work around. It might not be the best one but will work.

In html file,

<div *ngIf="show()"> </div>

In component TS file,

show(){
  if(test){ //condition for showing the div
    myVariable = true; 
    return true;
  }
  else
    return false;
}

Solution 2

I would like to build on Rachit's answer.

<div *ngIf="test"><ng-container *ngIf="runShow && show()"></ng-container></div>

and in the component

this.runShow = true;

//show always returns true.
show() {
  //Return if not running. Shouldn't be needed as runShow proceeds show in the template.
  if(!this.runShow) {
    return true;
  }
  //Do modifications...

  this.runShow = false;
  return true;

show() will only run if test is truthy, and will turn itself off after a single iteration (of course, you can change this.runShow to be based off something). An important gotcha is that until this.runShow == false, this will run every time the component detects a change, no more and no less. We put the show() inside its own ng-container so that it doesn't impact the DOM and is run after the test is rendered.

Solution 3

A solution would be to use @ViewChildren and to subscribe to the changes Observable of QueryList in ngAfterViewInit(), also to avoid ExpressionChangedAfterItHasBeenCheckedError ( this happens if for example you want to change a property that is used in the template when the div is visible) you can use detectChanges() of ChangeDetectorRef like this:

@Component({
  selector: "my-app",
  template: `
    <div *ngIf="num % 10 === 0" #doSomethingWhenVisibleDIV>
      Show some content
    </div>
    <div *ngIf="showOtherDiv">Show different content here</div>
  `,
  styleUrls: ["./app.component.css"]
})
export class AppComponent implements OnInit, AfterViewInit, OnDestroy {
  num: number = 0;
  showOtherDiv: boolean = false;

  private subscription: Subscription;

  @ViewChildren("doSomethingWhenVisibleDIV") divs: QueryList<ElementRef>;

  constructor(private changeDetectorRef: ChangeDetectorRef) {}

  ngOnInit() {
    setInterval(() => this.num++, 1000);
  }

  ngAfterViewInit() {
    this.subscription = this.divs.changes.subscribe({
      next: () => {
        if (this.divs.length > 0) {
          this.showOtherDiv = !this.showOtherDiv;
          this.changeDetectorRef.detectChanges();
        }
      }
    });
  }

  ngOnDestroy() {
    this.subscription.unsubscribe();
  }
}

Stackblitz example

Share:
20,197
Manzur Khan
Author by

Manzur Khan

Mechanical Engineer by Education, Tech Enthusiast by Passion, Web Developer by Profession.

Updated on July 09, 2022

Comments

  • Manzur Khan
    Manzur Khan almost 2 years

    I'm having some divs with ngIf, I just want to have a way to know if the particular div is the one which is visible/active right now like an event trigger like focus (it doesn't work) or something, and with this event, I will set a variable or something.

    <div *ngIf="test === true" (focus)="myVariable = true">
    </div>
    
  • Manzur Khan
    Manzur Khan almost 6 years
    Yea, I can surely set my variable with this, but the problem here is show() gets called innumerable times based on all the conditions, that defeats the purpose since it only considers the last condition and that's not the active condition