I have a few image and info text, so when I click on image, specific info text used to toggle/show. Also if previous info text is opened this will hide and next info text will show on click on any other image. Now my requirement is to close the info text on outside if it is opened. Here is the code below. https://stackblitz.com/edit/angular-mb2rmb?file=src%2Fapp%2Fapp.component.html
<hello name="{{ name }}"></hello>
<h3>How to show info of clicked image only</h3>
<div *ngFor="let x of things; let i = index">
<img
src="https://source.unsplash.com/200x200"
alt="loading"
(click)="clicked(i)"
/>
<div *ngIf="x.show">
<div class="names">
<div class="fullName">{{ x.data }}</div>
<div>{{ x.data2 }}</div>
</div>
</div>
</div>
import { Component,Renderer2,ElementRef,ViewChild } from '@angular/core';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
name = 'Angular';
previousIndex: number = -1;
public show: boolean = false;
@ViewChild('toggleButton') toggleButton: ElementRef;
@ViewChild('menu') menu: ElementRef;
clicked(index) {
// Checking if same picture clicked or new
if (this.previousIndex >= 0 && this.previousIndex != index) {
// If new picture is clicked then closing previous picture
this.things[this.previousIndex].show = false;
}
// Updating index
this.previousIndex = index;
this.things[index].show = !this.things[index].show;
}
public things: Array<any> = [
{
data: 'information for img1:',
data2: 'only the info img1 is displayed',
show: false,
},
{
data: 'information for img2:',
data2: 'only the info for img2 is displayed',
show: false,
},
{
data: 'information for img3:',
data2: 'only the info for img3 is displayed',
show: false,
},
];
}
METHOD 1
Change the clicked function to have the event as a parameter
(click)="clicked(i, $event)"
&
clicked(index, event) {
// Checking if same picture clicked or new
if (this.previousIndex >= 0 && this.previousIndex != index) {
// If new picture is clicked then closing previous picture
this.things[this.previousIndex].show = false;
}
// Updating index
this.previousIndex = index;
this.things[index].show = !this.things[index].show;
event.stopPropagation();
}
Add another function for the host:
hostClick(e) {
this.things.forEach((element)=>{
element.show = false;
});
}
and update the component meta with host click event
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
host: {
"(click)": "hostClick($event)"
}
})
For reference, Working example for method 1
Basically, event.stopPropagation(); prevents further propagation of the current event to host click events. The host click event is fired anywhere inside the host ( component ).
METHOD 2
Import HostListener to the component
import { Component,Renderer2,ElementRef,ViewChild, HostListener } from '@angular/core';
and use the HostListener to bind the function
@HostListener("click", ["$event"])
hostClick(event: any): void {
this.things.forEach((element)=>{
element.show = false;
});
}
update the clicked function same as in method 1
(click)="clicked(i, $event)"
&
clicked(index, event) {console.log(index);
// Checking if same picture clicked or new
if (this.previousIndex >= 0 && this.previousIndex != index) {
// If new picture is clicked then closing previous picture
this.things[this.previousIndex].show = false;
}
// Updating index
this.previousIndex = index;
this.things[index].show = !this.things[index].show;
event.stopPropagation();
}
For reference, Working Example for method 2