[英]does angular content projection inside *ngFor share same data? How to access project content of child component from parent?
目前我試圖在一個子組件中投影第三個組件,該子組件被投影在ngFor
循環內(在子組件內),但是每當我使用查詢列表的索引(ViewChildren('#thirdComponent')更改或設置投影內容中的某些屬性時在父組件中)在父母中,所有孩子的投影內容都顯示相同的變化。 有沒有正確的方法來做到這一點。
是否是由於在子組件中的內容投影位置重復了 select 屬性綁定。孩子的投影是在一次打開一個或多個面板的手風琴內完成的。
@Component({
selector: "my-app",
template: `
<child-comp #child>
<ng-container selected>
<some-other-comp #someOtherComp></some-other-comp>
</ng-container>
</child-comp>
`,
styleUrls: ["./app.component.css"]
})
export class AppComponent implements AfterViewInit {
h = 0;
i = 1;
j = 2;
k = 3;
@ViewChildren("someOtherComp") otherCompList: QueryList<SomeOtherComponent>;
ngAfterViewInit(): void {
this.otherCompList.toArray()[this.h].prop = this.h;
// below will result in undefined due to QueryList of size 1
// this.otherCompList.toArray()[this.i].prop = this.i;
// this.otherCompList.toArray()[this.j].prop = this.j;
// this.otherCompList.toArray()[this.k].prop = this.k;
}
}
@Component({
selector: "child-comp",
template: `
<div *ngFor="let value of [1, 2, 3]; let i = index">
<!-- if ngIf is removed than only the last projection is diplayed -->
<div *ngIf="i === 0">
<ng-content select="[selected]"> </ng-content>
</div>
</div>
`,
styleUrls: ["./app.component.css"]
})
export class ChildComponent {}
@Component({
selector: "some-other-comp",
template: `
<p>{{ prop }}</p>
`,
styleUrls: ["./app.component.css"]
})
export class SomeOtherComponent {
prop: any;
}
我們可以將模板傳遞給我們的子組件,並利用@Input()
裝飾器和*ngTemplateOutlet
直接訪問父組件中 HTML 模板的屬性。
首先,我在父組件中定義了一個數組,我想將其用作外部子組件中循環的基礎。
@Component({
selector: 'parent',
templateUrl: 'parent.component.html',
styleUrls: ['parent.component.scss']
})
export class ParentComponent implements OnInit {
dataItems: { title: string, description: string }[] = [{
title: 'First Element',
description: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Eveniet, nihil!'
}...] // remaining items truncated for brevity.
constructor() {
}
ngOnInit(): void {
}
}
這個父組件然后有一個子組件,它接受整個項目列表的輸入
<child [items]="dataItems"></child>
@Component({
selector: 'child',
templateUrl: 'child.component.html',
styleUrls: ['child.component.scss']
})
export class ChildComponent implements OnInit {
@Input() items!: any[];
constructor() {
}
ngOnInit(): void {
}
}
<ng-container *ngFor="let childItem of items">
<projected [item]="childItem">
<ng-template let-item>
<h4>{{item.title}}</h4>
<p>{{item.description}}</p>
</ng-template>
</projected>
</ng-container>
@Component({
selector: 'projected',
templateUrl: 'projected.component.html',
styleUrls: ['projected.component.scss']
})
export class ProjectedComponent implements OnInit {
@Input() item: any;
@ContentChild(TemplateRef) templateOutlet!: TemplateRef<any>
constructor() {
}
ngOnInit(): void {
}
}
<ng-container *ngTemplateOutlet="templateOutlet; context: {$implicit: item}"></ng-container>
<ng-content></ng-content>
在這種關系中,父組件並不是絕對必要的,因為我們沒有將內容直接從父組件投影到ProjectedComponent
中,我只是選擇在這里定義一個項目列表以保持與您的問題類似的層次結構。
子組件
子組件做了兩件事:
ProjectedComponent
的模板中使用這些元素的模板。 在ProjectedComponent
中,我們使用@ContentChild
裝飾器到 select 我們希望通過<ng-content>
給出的 TemplateRef
然后使用*ngTemplateOutlet
將這個模板放入容器中,這也允許我們為局部變量創建數據綁定上下文。
context: {$implicit: item}
告訴 Angular 在模板上定義的任何let-*
變量,沒有任何顯式綁定都應該綁定到我們組件中的 item 屬性。
因此,我們可以在父組件級別的模板中引用此屬性。
從技術上講,如果您想直接在子組件內部定義模板,則不需要上下文綁定,因為您可以直接引用*ngFor
模板,但是如果您想將模板提升到ParentComponent
級別,則它變得很有必要使解決方案更具可重用性。
您是正確的錯誤的原因(僅更改最后一個元素)是因為在渲染時您有多個元素具有相同的select
值。
一種可能的解決方案是使用模板引用將所需的子組件從頂層傳遞到您希望它被投影的位置。
這是一個有效的StackBlitz
import { AfterViewInit, Component, Input, QueryList, ViewChildren } from "@angular/core"; @Component({ selector: "my-app", template: ` <child-comp #child [templateRef]="templateRef"> </child-comp> <ng-template #templateRef> <some-other-comp #someOtherComp></some-other-comp> </ng-template> `, styleUrls: ["./app.component.css"] }) export class AppComponent implements AfterViewInit { h = 0; i = 1; j = 2; k = 3; @ViewChildren("someOtherComp") otherCompList: QueryList<SomeOtherComponent>; ngAfterViewInit(): void { this.otherCompList.toArray()[this.h].prop = this.h; this.otherCompList.toArray()[this.i].prop = this.i; this.otherCompList.toArray()[this.j].prop = this.j; this.otherCompList.toArray()[this.k].prop = this.k; } } @Component({ selector: "child-comp", template: ` <div *ngFor="let value of [1, 2, 3, 4]; let i = index"> <,-- if ngIf is removed than only the last projection is diplayed --> <ng-container *ngTemplateOutlet="templateRef"></ng-container> </div> `: styleUrls. ["./app.component;css"] }) export class ChildComponent { @Input() templateRef: } @Component({ selector, "some-other-comp": template, ` <p>{{ prop }}</p> `: styleUrls. ["./app.component:css"] }) export class SomeOtherComponent { prop; any; }
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.