我正在尝试新的AngularElements功能。 (https://angular.io/guide/elements)
首次测试是成功的但是只要我整合@ContentChildren它就会停止工作。这对我来说似乎是逻辑,因为新创建的Component作为CustomElement无法通过Angular-Context获取引用,因为它位于应用程序之外。
我的目标是制作一个最小的Tab-Wrapper / Tab - 类似于angular.io中使用的组件结构
<custom-tab-wrapper>
<anb-tab [title]="'Test'">
Content
</anb-tab>
</custom-tab-wrapper>
我还创建了一个Stackblitz,但这似乎更糟糕,因为HMR多次定义组件会导致错误。但这应该可以让你更好地了解我想要实现的目标。
https://stackblitz.com/edit/angular-byvpdz?file=src%2Fapp%2Ftab-wrapper%2Ftab-wrapper.component.ts
以下是主要文件:
的index.html
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>AngularBlog</title>
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<body>
<anb-root></anb-root>
<custom-tab-wrapper>
<anb-tab [title]="'Test'">
Content
</anb-tab>
</custom-tab-wrapper>
</body>
</html>
制表wrapper.component.ts
import {AfterContentInit, Component, ContentChildren, OnInit, QueryList, ViewEncapsulation} from '@angular/core';
import {TabComponent} from '../tab/tab.component';
import {AfterContentInit, Component, ContentChildren, OnInit, QueryList, ViewEncapsulation} from '@angular/core';
import {TabComponent} from '../tab/tab.component';
@Component({
selector: 'anb-tab-wrapper',
template: `
<div class="tab-selection-wrapper">
<h1>Test</h1>
<div class="tab-selection" (click)="enableTab(tab)" *ngFor="let tab of tabs.toArray()">
{{tab.title}}
</div>
</div>
<div class="tab-content">
<ng-content></ng-content>
</div>
`,
encapsulation: ViewEncapsulation.Native
})
export class TabWrapperComponent implements OnInit, AfterContentInit {
@ContentChildren(TabComponent) tabs: QueryList<TabComponent>;
constructor() {
setInterval(() => {
console.log(this.tabs);
}, 2000);
}
public enableTab(tab: TabComponent) {
tab.active = true;
this.tabs.toArray().forEach(tabToCheck => {
if (tab !== tabToCheck) {
tabToCheck.active = false;
}
});
}
ngAfterContentInit(): void {
}
ngOnInit() {
}
}
然后我会有一个Tab-Component。如果我在angular-root-element中使用它而不是作为WebComponent,则会正确呈现。
app.module.ts
import {BrowserModule} from '@angular/platform-browser';
import {Injector, NgModule} from '@angular/core';
import {AppComponent} from './app.component';
import {TabWrapperComponent} from './tab-wrapper/tab-wrapper.component';
import {TabComponent} from './tab/tab.component';
import {createCustomElement} from '@angular/elements';
@NgModule({
declarations: [
AppComponent,
TabWrapperComponent,
TabComponent
],
entryComponents: [
TabWrapperComponent,
TabComponent
],
imports: [
BrowserModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule {
constructor(private injector: Injector) {
const tabWrapper = createCustomElement(TabWrapperComponent, {injector: injector});
customElements.define('custom-tab-wrapper', tabWrapper);
const tabComponent = createCustomElement(TabComponent, {injector: injector});
customElements.define('anb-tab', tabComponent);
}
}
我知道我可以在没有@ContentChildren的情况下解决这个问题但是我想在CustomComponent中使用这个功能。 所以我的问题是:是否可以使用@ContentChildren / ViewChildren。 如果不是,有哪些替代方案?
感谢您的帮助
丹尼尔
答案 0 :(得分:2)
Rob Worlmald回答了我的问题,我将其作为Twitter消息发送给了他。我想与社区分享结果:
如果Directives和ContentChild / ContentChildren的工作方式如下,他会回答这个问题:
不,他们没有 - 在当前视图中,引擎查询是静态的。在 一般来说,因为你可能会投射任何一个香草DOM 节点或其他(Angular)自定义元素,您可以使用 querySelector(全部)
这基本上意味着我们可以使用document.querySelector()在angular-livecyclce或outside之外选择子节点。我个人认为在Angular之外取出它似乎是更清洁的方法,因为少数额外的线路不会被使用但仍然在角度应用中执行。我会做一些研究。
可以在此处找到有关此主题的进一步讨论和可能的解决方法: https://twitter.com/robwormald/status/1005613409486848000
他继续说道:
你可以结合使用 https://developer.mozilla.org/en-US/docs/Web/Events/slotchange ......来 近似相同的行为
并在未来以一个可能更清洁的解决方案结束:
在常春藤(v7或之后不久),我们可能会制作查询系统 更灵活,更有活力
将在不久的将来使用querySelectorAll更新我的解决方案。