Angular 6 在 AngularElements 中使用 ContentChildren/ViewChildren - CustomComponents

标签 angular web-component angular6

我正在尝试新的 AngularElements 功能。 (https://angular.io/guide/elements)

第一次测试成功,但一旦我集成@ContentChildren,它就停止工作。这对我来说似乎是逻辑的,因为新创建的组件作为 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>

tab-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() {
  }

}

然后我就会有一个选项卡组件。如果我在 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。 如果不是,还有哪些替代方案?

感谢您的帮助

丹尼尔

最佳答案

Rob Worlmald回答了我通过 Twitter 消息发送给他的问题。我想与社区分享结果:

他回答了 Directives 和 ContentChild/ContentChildren 是否按如下方式工作的问题:

Nope, they do not - in the current view engine queries are static. In general, because you’re likely to be projecting either vanilla DOM nodes or other (Angular) Custom Elements, you can just use querySelector(All)

这基本上意味着我们可以使用 document.querySelector() 选择 angular-livecycle 内或外部的子项。在我个人看来,在 Angular 之外获取它似乎是更干净的方法,因为不会使用一些额外的行,但仍然在 Angular 应用程序中执行。我会做一些研究。

有关此主题的进一步讨论和可能的解决方法可以在此处找到: https://twitter.com/robwormald/status/1005613409486848000

他继续说道:

Which you can combine with https://developer.mozilla.org/en-US/docs/Web/Events/slotchange … to approximate the same behaviors

并以 future 可能更清洁的解决方案结束:

In ivy (v7 or shortly thereafter) we’ll likely make the query system more flexible and dynamic

将在不久的将来使用 querySelectorAll 更新我的解决方案。

关于Angular 6 在 AngularElements 中使用 ContentChildren/ViewChildren - CustomComponents,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50554956/

相关文章:

Angular2 - Keyup 需要澄清

css - 旋转 Angular - V 形 - 单击

javascript - Nativescript 和 Angular 2 Http 服务

javascript - Meteorjs + Angular2点击链接不重新渲染页面

javascript - 自定义元素中的脚本标签

angular - 类型 'zip' 上不存在属性 'typeof Observable'。 Angular 6

javascript - Angular 2 中的动态组件

javascript - 使用 JavaScript 动态应用 CSS

javascript - 在 Mat-Select : Angular 6 中滚动到 Mat-0options 末尾时触发事件

css - 无法使用我的 css 属性覆盖 Angular Material 主题