Reputation: 2486
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>
Upvotes: 16
Views: 29640
Reputation: 66
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();
}
}
Upvotes: 4
Reputation: 79
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.
Upvotes: 2
Reputation: 135
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;
}
Upvotes: 3
Reputation:
Your div will be rendered and visible once the change detection is triggered. When a change is detected, the whole lifecycle is ran again.
If you want to run something, you should hook on one of the events of the lifecycle. I suggest AfterViewInit
.
Now that you know how, let's see what you should do.
In your case, you should create div with template references. This will allow you to have a reference to the element and make you able to check which div is shown or hidden.
Here is a stackblitz that shows you how it works, and here is the code :
import { Component, ViewChildren, QueryList, ElementRef } from '@angular/core';
@Component({
selector: 'my-app',
template: `
<div *ngFor="let item of [0, 1, 2, 3, 4, 5]; let i = index">
<span *ngIf="i === show" #shownDiv [id]="'div-' + i">{{ item }}</span>
</div>
`
})
export class AppComponent {
name = 'Angular 6';
show = 0;
@ViewChildren('shownDiv') divs: QueryList<ElementRef>;
ngOnInit() {
setInterval(() => {
this.show++;
if (this.show > 5) {
this.show = 0;
}
}, 1000);
}
ngAfterViewChecked() {
let shown = this.divs.find(div => !!div);
console.log('DIV shown is ' + (shown.nativeElement as HTMLSpanElement).id);
// Now that you know which div is shown, you can run whatever piece of code you want
}
}
Upvotes: 6