简体   繁体   English

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

[英]Angular 6 using ContentChildren/ViewChildren in AngularElements - CustomComponents

I am trying out the new AngularElements feature.我正在尝试新的 AngularElements 功能。 ( https://angular.io/guide/elements ) ( https://angular.io/guide/elements )

First tests were successfull but as soon as I integrate @ContentChildren it stops working.第一次测试成功了,但是一旦我集成了@ContentChildren,它就会停止工作。 This seems logic to me, as the newly created Component as the CustomElement cannot get the reference via Angular-Context as it lives outside of the app.这对我来说似乎是合乎逻辑的,因为新创建的组件作为 CustomElement 无法通过 Angular-Context 获得引用,因为它位于应用程序之外。

My aim was to make a minimal Tab-Wrapper / Tab - Component like structure as they use in angular.io我的目标是制作一个最小的 Tab-Wrapper / Tab - 类似于它们在 angular.io 中使用的结构

<custom-tab-wrapper>
  <anb-tab [title]="'Test'">
    Content
  </anb-tab>
</custom-tab-wrapper>

I also created a Stackblitz but this seems to be even worse as HMR defines the component multiple times which results in an error.我还创建了一个 Stackblitz,但这似乎更糟,因为 HMR 多次定义组件导致错误。 But this should give you a better idea on what I am trying to achieve.但这应该能让你更好地了解我想要实现的目标。

https://stackblitz.com/edit/angular-byvpdz?file=src%2Fapp%2Ftab-wrapper%2Ftab-wrapper.component.ts https://stackblitz.com/edit/angular-byvpdz?file=src%2Fapp%2Ftab-wrapper%2Ftab-wrapper.component.ts

Here are the main files:以下是主要文件:

index.html索引.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 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() {
  }

}

And then I would have a Tab-Component.然后我会有一个选项卡组件。 Which gets rendered correctly if I use it within the angular-root-element but not as a WebComponent.如果我在 angular-root-element 中使用它而不是作为 WebComponent 使用它,它会正确呈现。

app.module.ts 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);
  }
}

I am aware that I can solve this without @ContentChildren but I would like to use this feature in CustomComponent.我知道我可以在没有 @ContentChildren 的情况下解决这个问题,但我想在 CustomComponent 中使用这个功能。 So my question is: Is it possible to use @ContentChildren / ViewChildren.所以我的问题是:是否可以使用@ContentChildren / ViewChildren。 If no, what are the alternatives?如果不是,有哪些替代方案?

Thanks for helping谢谢你的帮助

Daniel丹尼尔

Rob Worlmald answered my question which I sent him as a Twitter-Message. Rob Wolmald回答了我的问题,我将其作为 Twitter 消息发送给了他。 I would like to share the results with the community:我想与社区分享结果:

He answers the question if Directives and ContentChild / ContentChildren works as following:他回答了 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)通常,因为您可能会投影普通 DOM 节点或其他(Angular)自定义元素,所以您可以只使用 querySelector(All)

Which basically means we can select the children within an angular-livecyclce or outside with document.querySelector().这基本上意味着我们可以使用 document.querySelector() 在 angular-livecyclce 内或外部选择孩子。 In my personal opinion fetching it outside Angular seems to be the cleaner approach as the few additional lines wouldn't be used but still executed within an angular-application.在我个人看来,在 Angular 之外获取它似乎是更简洁的方法,因为不会使用几行额外的行,但仍会在 angular 应用程序中执行。 I will do some research.我会做一些研究。

Further discussions on this topic and a possible workaround can be found here: https://twitter.com/robwormald/status/1005613409486848000可以在此处找到有关此主题的进一步讨论和可能的解决方法: https : //twitter.com/robwormald/status/1005613409486848000

He continues:他继续:

Which you can combine with https://developer.mozilla.org/en-US/docs/Web/Events/slotchange … to approximate the same behaviors您可以将其与https://developer.mozilla.org/en-US/docs/Web/Events/slotchange结合使用……以近似相同的行为

And ends with a possibly cleaner solution in the future:并以将来可能更清洁的解决方案结束:

In ivy (v7 or shortly thereafter) we'll likely make the query system more flexible and dynamic在 ivy(v7 或之后不久)中,我们可能会使查询系统更加灵活和动态

Will update my solution with querySelectorAll in the near future.将在不久的将来使用 querySelectorAll 更新我的解决方案。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 angular 9 使用查询列表(contentChildren 或 ViewChildren)对同级 dom 重新排序/排序 - angular 9 reorder/sort siblings dom by using querylist(contentChildren or ViewChildren) 如何在 Angular(v14) 中更新@ViewChildren(或@ContentChildren)的 styles - How to update the styles of @ViewChildren (Or @ContentChildren) in Angular(v14) 在结构指令中访问 ViewChildren/ContentChildren - Accessing ViewChildren/ContentChildren in a structural Directive Angular6 @ViewChildren使用标识符 - Angular6 @ViewChildren using identifier 如何在ES5中访问Component的ViewChildren和ContentChildren? - How to access ViewChildren and ContentChildren of Component in ES5? 将@ViewChildren/@ContentChildren 与 router-outlet 结合使用 - Use @ViewChildren/@ContentChildren in combination with router-outlet Angular 4使用ngComponentOutlet来显示动态变化的ContentChildren - Angular 4 using ngComponentOutlet to display dynamically changing ContentChildren Angular 2-使用@ContentChildren过滤组件的内容 - Angular 2 - Using @ContentChildren for filtering a component's content 使用@ViewChildren 的 Angular 5 访问 div 列表 - Angular 5 access divs list using @ViewChildren 如何使用Angle中的ContentChildren访问嵌套元素 - how to access nested elements using ContentChildren in angular
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM