因此,假设我有一个组件ExampleComponent
,它在其内容视图中构建了QueryList
个组件中的SomeOtherComponent
个。
import {Component, ContentChildren, QueryList} from '@angular/core'
import {SomeOtherComponent} from '../some-other-component/some-other-component.component'
@Component({
selector : 'app-example',
templateUrl: './example.component.html',
styleUrls : ['./example.component.css']
})
export class ExampleComponent {
@ContentChildren(SomeOtherComponent)
someOtherComponents: QueryList<SomeOtherComponent>
}
在它的模板中,我有一个NgFor,应该在每个NgFor之后插入一个<hr />
元素。
<ng-container *ngFor="let component of someOtherComponents">
<!-- put component here -->
<hr />
</ng-container>
例如,这个(在其他组件中):
<app-example>
<app-some-other-component>blablabla</app-some-other-component>
<app-some-other-component>hello world</app-some-other-component>
<app-some-other-component>testing</app-some-other-component>
</app-example>
会导致此结果(在HTML中):
<app-example>
<app-some-other-component>blablabla</app-some-other-component>
<hr />
<app-some-other-component>hello world</app-some-other-component>
<hr />
<app-some-other-component>testing</app-some-other-component>
<hr />
</app-example>
但是,这就是问题所在。如何插入该SomeOtherComponent
实例? ng-content
的{{1}}属性不支持组件实例,CDK portals不喜欢我,我不想使用模板创建一些复杂的解决方案,并且要求用户包装所有内容他们的孩子在模板中...我该怎么办?
为了澄清:我不想创建select
实例。我想做类似于SomeOtherComponent
的事情,但是要插入一个特定的实例(例如QueryList
返回的ContentChildren
内的实例)。我也不想使用指令/模板(例如将<ng-content select="app-some-other-component">
放在所有子代上)。
注意:还有其他方法可以在组件后插入水平线,并随时提及它们,只需确保也回答问题即可。这只是一个例子。
答案 0 :(得分:6)
您的问题是“如何插入特定的组件实例?”但是我从您的解释中了解到,您想通过ng-content
在已插入组件实例的正下方添加行。因为您已经有QueryList
返回的ContentChildren
元素。
从这一点开始,我们需要了解有关ViewContainerRef的一件重要事情;
有趣的是,Angular不会在元素内插入视图,而是将其追加到绑定到ViewContainer的元素之后。
因此,如果我们可以访问ViewContainerRef
中QueryList
个元素,则可以轻松地向这些元素追加新元素。而且我们可以使用ViewContainerRef
查询的read元数据属性来访问ContentChildren
个元素;
@ContentChildren(SomeOtherComponent, { descendants: true, read: ViewContainerRef }) someOtherComponents: QueryList<ViewContainerRef>;
由于我们有ViewContainerRef
个元素,因此可以使用createEmbeddedView()
@Component({
selector: 'app-example',
templateUrl: './example.component.html',
styleUrls: ['./example.component.css']
})
export class ExampleComponent implements AfterContentInit {
@ViewChild("templateToAppend", {static: true}) templateToAppend: TemplateRef<any>;
@ContentChildren(SomeOtherComponent, { descendants: true, read: ViewContainerRef }) someOtherComponents: QueryList<ViewContainerRef>;
ngAfterContentInit() {
this.someOtherComponents.forEach(ap => ap.createEmbeddedView(this.templateToAppend));
}
}
模板
<ng-content></ng-content>
<ng-template #templateToAppend>
<hr style="color: blue"/>
</ng-template>
演示here
通过使用这种方法来创建指令,以满足您对<ng-content select="app-some-other-component">
类似的要求
我们可以创建一个将TemplateRef
用作@Input()
的指令,并将其附加到ViewContainerRef
export class CustomAppendable { }
@Directive({
selector: '[appMyCustomAppender]'
})
export class MyCustomAppenderDirective {
@ContentChildren(CustomAppendable, { descendants: true, read: ViewContainerRef }) appendables: QueryList<ViewContainerRef>;
@Input() appMyCustomAppender: TemplateRef<any>;
constructor() { }
ngAfterContentInit() {
setTimeout(() => {
this.appendables.forEach(ap => ap.createEmbeddedView(this.appMyCustomAppender));
});
}
}
使用这种方法,为避免在我们的SomeOtherComponent
与指令之间建立紧密的联系,我们通过创建一个通用类型CustomAppendable
并使我们的组件以某种方式通用,并将其用作该组件的别名我们要在ContentChildren
注意:我找不到使ContentChildren
查询与模板选择器一起工作的方法。如here所述,我们可以将ContentChildren
与模板引用变量或组件类型一起使用。这就是为什么我创建别名的原因。
@Component({
selector: 'app-some-other-component',
templateUrl: './some-other-component.component.html',
styleUrls: ['./some-other-component.component.css'],
providers: [{ provide: CustomAppendable, useExisting: SomeOtherComponent }]
})
export class SomeOtherComponent implements OnInit {
constructor() { }
ngOnInit() {}
}
同样使用这种方法,我们不需要容器组件,也不需要将指令应用于任何元素。
<div [appMyCustomAppender]="templateToAppend">
<app-some-other-component>underlined</app-some-other-component>
<app-some-other-component>underlined</app-some-other-component>
<app-some-other-component2>not underlined</app-some-other-component2>
<br />
<app-some-other-component2>not underlined</app-some-other-component2>
</div>
<br />
<app-some-other-component>but not underlined!</app-some-other-component>
<ng-template #templateToAppend>
<hr style="color: red"/>
<br />
</ng-template>
演示here
我希望我能够正确理解您的要求,并且所有这些都对您有所帮助:)
答案 1 :(得分:-2)
据我对您问题的理解,听起来您想动态插入组件。这可以通过将所需的SomeOtherComponent
的数量推入数组中,然后在ngFor
内创建someOtherComponent来完成:
import {Component, ContentChildren, QueryList} from '@angular/core'
import {SomeOtherComponent} from '../some-other-component/some-other-component.component'
@Component({
selector : 'app-example',
templateUrl: './example.component.html',
styleUrls : ['./example.component.css']
})
export class ExampleComponent {
someOtherComponents: any[];
constructor(){
this.someOtherComponents.push({data: "insert_stuff_here"});
this.someOtherComponents.push({data: "insert_stuff_here"})
}
}
然后在您的ngFor中
<ng-container *ngFor="let component of someOtherComponents">
<someOtherComponent [possibleInputHere]="component.data"></someOtherComponent>
<hr />
</ng-container>
希望这就是您要寻找的!