Angular 6 с использованием ContentChildren / ViewChildren в AngularElements - CustomComponents - PullRequest
0 голосов
/ 27 мая 2018

Я пробую новую функцию AngularElements.(https://angular.io/guide/elements)

Первые тесты были успешными, но как только я интегрирую @ContentChildren, он перестает работать. Мне кажется, это логично, так как вновь созданный Компонент как CustomElement не может получить ссылку через Angular-Context, так какживет за пределами приложения.

Моя цель состояла в том, чтобы создать минимальную вкладку-оболочку / вкладку - структуру, подобную компонентам, которую они используют в 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() {
  }

}

И тогда у меня будет Tab-Component.Который отображается правильно, если я использую его в angular-root-элементе, но не как веб-компонент.

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.Если нет, каковы альтернативы?

Спасибо за помощь

Даниил

1 Ответ

0 голосов
/ 18 июня 2018

Роб Уорлмальд ответил на мой вопрос, который я отправил ему в виде твиттер-сообщения.Я хотел бы поделиться результатами с сообществом:

Он отвечает на вопрос, работает ли Directives и ContentChild / ContentChildren следующим образом:

Нет, в текущем представлении это не так.запросы к двигателю статичны.В общем, поскольку вы, вероятно, будете проецировать либо ванильные DOM-узлы, либо другие (угловые) пользовательские элементы, вы можете просто использовать querySelector (All)

, что в основном означает, что мы можем выбрать дочерние элементы в пределахangular-livecyclce или снаружи с помощью document.querySelector ().По моему личному мнению, извлечение его за пределы Angular кажется более чистым подходом, поскольку несколько дополнительных строк не будут использоваться, но все же будут выполняться в angular-приложении.Я проведу некоторые исследования.

Дальнейшие обсуждения по этой теме и возможные обходные пути можно найти здесь: https://twitter.com/robwormald/status/1005613409486848000

Он продолжает:

Что вы можетев сочетании с https://developer.mozilla.org/en-US/docs/Web/Events/slotchange… для приблизительного аналогичного поведения

И в будущем возможно более чистое решение:

В плюще (v7 или вскоре после этого) мы, вероятно, сделаем систему запросов более гибкой и динамичной

Обновим мое решение с querySelectorAll в ближайшем будущем.

...