从子组件访问父组件。使用服务? @ContentChildren 呢?
Access Parent component from Child component. Use service? What about @ContentChildren?
我创建了一个 Angular 7 手风琴组件 SlackBlitz Example:
export class AccordionComponent {
@ContentChildren(PanelComponent) panels: QueryList<PanelComponent>;
ngAfterContentInit() {
this.panels.forEach((panel) => {panel.active = false;});
}
}
PanelComponent 如下:
export class PanelComponent {
@Input() active: boolean;
@Input() title: string;
toggle() {
this.active = !this.active;
}
}
手风琴正在工作,但我需要在打开新面板时关闭所有面板。
我认为这可以通过两种方式完成:
在 PanelComponent 中能够访问 AccordionComponent 上的方法。
该方法将使一个面板处于活动状态,其余面板处于非活动状态。
我不知道如何从子组件(面板)访问父组件(手风琴)
使用包含面板的手风琴服务:
panels: PanelComponent[] = [];
然后在 Accordion 和 Panel 中注入这个服务。
这似乎合乎逻辑,但后来我停止使用@ContentChildren(PanelComponent)。
从某种意义上说,这打破了 Accordion 和 Panel 之间的关系。
我应该使用哪种解决方案?或者另一个?
我的 2 个解决方案是否遗漏了什么(我不知道如何实施解决方案 1)。
关于第1点,可以注入父组件,如下:
constructor(
@Inject(forwardRef(() => AccordionComponent)) private accordion: AccordionComponent,
...)
使用服务也可以,但恕我直言,对于这个简单的案例来说似乎需要更多的工作。
您可以轻松地使用事件发射器来解决您的问题。
对您的代码所做的更改:
panel.component.ts
@Input() activate: string;
@Input() title: string;
@Output() closeOtherPanels: EventEmitter<string> = new EventEmitter();
active : boolean = false;
ngOnChanges(changes : SimpleChanges){
if(changes.activate){
this.active = this.activate == this.title;
}
}
toggle() {
this.active = !this.active;
if(this.active){
this.closeOtherPanels.emit(this.title);
}
}
app.component.ts
export class AppComponent {
activeTitle : string="";
name = 'Angular';
closeOtherPanels(value){
this.activeTitle=value;
}
}
app.component.html
<accordion>
<panel title="Panel 1 title" [activate]="activeTitle"
(closeOtherPanels)="closeOtherPanels($event)">Panel 1 content</panel>
<panel title="Panel 2 title" [activate]="activeTitle" (closeOtherPanels)="closeOtherPanels($event)">Panel 2 content</panel>
<panel title="Panel 3 title" [activate]="activeTitle" (closeOtherPanels)="closeOtherPanels($event)">Panel 3 content</panel>
<panel title="Panel 4 title" [activate]="activeTitle" (closeOtherPanels)="closeOtherPanels($event)">Panel 4 content</panel>
</accordion>
我创建了一个 Angular 7 手风琴组件 SlackBlitz Example:
export class AccordionComponent {
@ContentChildren(PanelComponent) panels: QueryList<PanelComponent>;
ngAfterContentInit() {
this.panels.forEach((panel) => {panel.active = false;});
}
}
PanelComponent 如下:
export class PanelComponent {
@Input() active: boolean;
@Input() title: string;
toggle() {
this.active = !this.active;
}
}
手风琴正在工作,但我需要在打开新面板时关闭所有面板。
我认为这可以通过两种方式完成:
在 PanelComponent 中能够访问 AccordionComponent 上的方法。
该方法将使一个面板处于活动状态,其余面板处于非活动状态。我不知道如何从子组件(面板)访问父组件(手风琴)
使用包含面板的手风琴服务:
panels: PanelComponent[] = [];
然后在 Accordion 和 Panel 中注入这个服务。
这似乎合乎逻辑,但后来我停止使用@ContentChildren(PanelComponent)。
从某种意义上说,这打破了 Accordion 和 Panel 之间的关系。
我应该使用哪种解决方案?或者另一个?
我的 2 个解决方案是否遗漏了什么(我不知道如何实施解决方案 1)。
关于第1点,可以注入父组件,如下:
constructor(
@Inject(forwardRef(() => AccordionComponent)) private accordion: AccordionComponent,
...)
使用服务也可以,但恕我直言,对于这个简单的案例来说似乎需要更多的工作。
您可以轻松地使用事件发射器来解决您的问题。
对您的代码所做的更改:
panel.component.ts
@Input() activate: string;
@Input() title: string;
@Output() closeOtherPanels: EventEmitter<string> = new EventEmitter();
active : boolean = false;
ngOnChanges(changes : SimpleChanges){
if(changes.activate){
this.active = this.activate == this.title;
}
}
toggle() {
this.active = !this.active;
if(this.active){
this.closeOtherPanels.emit(this.title);
}
}
app.component.ts
export class AppComponent {
activeTitle : string="";
name = 'Angular';
closeOtherPanels(value){
this.activeTitle=value;
}
}
app.component.html
<accordion>
<panel title="Panel 1 title" [activate]="activeTitle"
(closeOtherPanels)="closeOtherPanels($event)">Panel 1 content</panel>
<panel title="Panel 2 title" [activate]="activeTitle" (closeOtherPanels)="closeOtherPanels($event)">Panel 2 content</panel>
<panel title="Panel 3 title" [activate]="activeTitle" (closeOtherPanels)="closeOtherPanels($event)">Panel 3 content</panel>
<panel title="Panel 4 title" [activate]="activeTitle" (closeOtherPanels)="closeOtherPanels($event)">Panel 4 content</panel>
</accordion>