I have a child component which displays information when you click on its button.
information-data.component.html
<div class="col-12 col-sm-12 col-md-12 col-lg-12">
<div class="col-sm-12 col-md-12 col-lg-12 p-2 info">
<h6 (click)="questionClick()">{{headName}}
<fa-icon [icon]="icons.faInfoCircle" class="fa-1x text-primary" transform="shrink-2"></fa-icon>
</h6>
</div>
<ng-template #childTemplate>
<div class="row" [hidden]="visibleStatus">
<div class="col-12 bulb-section">
<div class="row m-0">
<div class="icon-bulb col">
<p class="ml-4">
{{infoData}}
</p>
</div>
</div>
</div>
</div>
</ng-template>
<ng-container *ngIf="!displayInfo; then childTemplate"></ng-container>
</div>
information-data.component.ts
export class InformationDataComponent {
@ViewChild('childTemplate', { static: true }) childTemplate: TemplateRef<any>;
constructor() { }
@Input() infoData: string;
@Input() visibleStatus: boolean;
@Input() headName: string;
@Input() displayInfo?: boolean;
questionClick () {
this.visibleStatus = !this.visibleStatus;
}
}
Scenario - In my parent component, I have 3 bootstrap cards which have different data each. When I click on a card, I only want the information for the respective card to be displayed, hiding the other two in this scenario.
<div class="card">
<div class="card-body">
<information-data [infoData]="salonInfo"
[headName]="salonHead"
[visibleStatus]="true"
[displayInfo]="true"
></information-data>
</div>
</div>
</div>
<div class="col-4 col-sm-4 col-md-4 col-lg-4">
<div class="card">
<div class="card-body">
<information-data [infoData]="hospitalInfo"
[headName]="hospitalHead"
[visibleStatus]="true"
[displayInfo]="true"
></information-data>
</div>
</div>
</div>
<div class="col-4 col-sm-4 col-md-4 col-lg-4">
<div class="card">
<div class="card-body">
<information-data [infoData]="travelInfo"
[headName]="travelHead"
[visibleStatus]="true"
[displayInfo]="true"
></information-data>
</div>
</div>
<div class="row pl-5 pr-5">
<ng-container *ngTemplateOutlet="childComponent.childTemplate"></ng-container>
</div>
</div>
Other scenarios - I use this child component widely in other parts of the application as shown below, and it should not be changed.
<retail-information-data [infoData]="funcInfo"
[headName]="funcHead"
[visibleStatus]="funcVisibility"
></retail-information-data>
How can I go about implementing this functionality without affecting other parts of the code?
We can use the EventEmitter
and @Output
to call the parent code, which will store the index of which element was clicked, then we can use a ViewChildren
to get all the child components that are present, then use the set index, to access the template.
I also use *ngFor as syntax
to access the child component template!
CHILD TS
import { CommonModule } from '@angular/common';
import {
Component,
Input,
ViewChild,
TemplateRef,
Output,
EventEmitter,
} from '@angular/core';
import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
import { faInfoCircle } from '@fortawesome/free-solid-svg-icons';
@Component({
selector: 'information-data',
standalone: true,
imports: [CommonModule, FontAwesomeModule],
templateUrl: './child.component.html',
styleUrl: './child.component.css',
})
export class ChildComponent {
@ViewChild('childTemplate', { static: true })
childTemplate!: TemplateRef<any>;
icons = {
faInfoCircle,
};
constructor() {}
@Input() infoData!: string;
@Input() visibleStatus!: boolean;
@Input() headName!: string;
@Input() displayInfo?: boolean;
@Output() clickEvent: EventEmitter<void> = new EventEmitter<void>();
questionClick() {
this.visibleStatus = !this.visibleStatus;
this.clickEvent.emit();
}
}
CHILD HTML
<div class="col-12 col-sm-12 col-md-12 col-lg-12">
<div class="col-sm-12 col-md-12 col-lg-12 p-2 info">
<h6 (click)="questionClick()">
{{ headName }}
<fa-icon
[icon]="icons.faInfoCircle"
class="fa-1x text-primary"
transform="shrink-2"
></fa-icon>
</h6>
</div>
<ng-template #childTemplate>
<div class="row" [hidden]="visibleStatus">
<div class="col-12 bulb-section">
<div class="row m-0">
<div class="icon-bulb col">
<p class="ml-4">
{{ infoData }}
</p>
</div>
</div>
</div>
</div>
</ng-template>
<ng-container *ngIf="!displayInfo; then childTemplate"></ng-container>
</div>
MAIN.TS
import { CommonModule } from '@angular/common';
import { Component, QueryList, ViewChild, ViewChildren, ChangeDetectorRef, } from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';
import 'zone.js';
import { ChildComponent } from './app/child/child.component';
@Component({
selector: 'app-root',
standalone: true,
imports: [CommonModule, ChildComponent],
template: `
<div class="card">
<div class="card-body">
<information-data
[infoData]="salonInfo"
[headName]="salonHead"
[visibleStatus]="true"
[displayInfo]="true"
(clickEvent)="index = 0;"
></information-data>
</div>
</div>
<div class="col-4 col-sm-4 col-md-4 col-lg-4">
<div class="card">
<div class="card-body">
<information-data
[infoData]="hospitalInfo"
[headName]="hospitalHead"
[visibleStatus]="true"
[displayInfo]="true"
(clickEvent)="index = 1;"
></information-data>
</div>
</div>
</div>
<div class="col-4 col-sm-4 col-md-4 col-lg-4">
<div class="card">
<div class="card-body">
<information-data
[infoData]="travelInfo"
[headName]="travelHead"
[visibleStatus]="true"
[displayInfo]="true"
(clickEvent)="index = 2;"
></information-data>
</div>
</div>
</div>
<div class="row pl-5 pr-5" *ngIf="getChild() as child">
<ng-container *ngTemplateOutlet="child"></ng-container>
</div>
`,
})
export class App {
@ViewChildren(ChildComponent) childComponents!: QueryList<ChildComponent>;
name = 'Angular';
travelHead = '12asdf3';
travelInfo = '12asdf3';
index = 0;
hospitalInfo = '12asdfasdf3';
hospitalHead = '12asdfasdf3';
salonHead = '12zxcvxcvz3';
salonInfo = '12zxcvxcvz3';
constructor(private cdr: ChangeDetectorRef) {}
ngAfterViewInit() {
this.cdr.detectChanges();
}
getChild() {
return this.childComponents?.get(this.index)?.childTemplate;
}
}
bootstrapApplication(App);