У меня есть дочерний компонент, который отображает информацию при нажатии на его кнопку.
информация-data.comComponent.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>
информация-data.comComponent.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;
}
}
Сценарий. В моем родительском компоненте у меня есть 3 загрузочные карты, каждая из которых имеет разные данные. Когда я нажимаю на карту, я хочу, чтобы отображалась только информация для соответствующей карты, скрывая две другие в этом сценарии.
<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>
Другие сценарии. Я широко использую этот дочерний компонент в других частях приложения, как показано ниже, и его не следует менять.
<retail-information-data [infoData] = "funcInfo"
[headName] = "funcHead"
[visibleStatus] = "funcVisibility"
></retail-information-data>
Как я могу реализовать эту функциональность, не затрагивая другие части кода?



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Используйте вывод
@Output() displayInfoChange:EventEmitter<boolean>=new EventEmitter<boolean>()
И когда изменится
questionClick () {
this.visibleStatus = !this.visibleStatus;
//
this.displayInfoChange.emit(this.visibleStatus);
}
Итак, вы можете использовать два способа привязки, и ваш родительский элемент учтет изменение и определит массив displayInfos.
displayInfos:boolean[]=[true,false,false]
<!--change each "0", by "1" and "2" to the second and third card-->
<information-data [infoData] = "salonInfo"
[headName] = "salonHead"
[visibleStatus] = "true"
[(displayInfo)] = "displayInfos[0]"
(displayInfoChange) = "displayInfos[0] && restToFalse(0)"
></information-data>
restToFalse(index:number)
this.displayInfos=this.displayInfos.map((x,i)=>(i==index))
}
Мы можем использовать EventEmitter и @Output для вызова родительского кода, в котором будет храниться индекс элемента, на который был нажата кнопка, затем мы можем использовать ViewChildren, чтобы получить все присутствующие дочерние компоненты, а затем использовать установленный индекс для доступа к шаблону. .
Я также использую *ngFor as syntax для доступа к шаблону дочернего компонента!
РЕБЕНОК ТС
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();
}
}
ДЕТСКИЙ 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>
ГЛАВНЫЙ.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);
@moonchild_ в main.ts также добавьте это constructor(private cdr: ChangeDetectorRef) {} ngAfterViewInit() { this.cdr.detectChanges(); }stackblitz
ExpressionChangedAfterItHasBeenCheckedError: выражение изменилось после проверки. Предыдущее значение: «не определено». Текущее значение: '[объект объекта]'. Он работает должным образом, но я получаю эту ошибку