使用 Angular 自定义 Web 组件抛出错误:选择器“app-root”不匹配任何元素

dud*_*ude 6 web-component custom-element angular angular10

我有一个带有延迟加载模块和路由的普通 Angular 10 应用程序。但是,我有一个特殊的要求需要满足。

在大多数页面上,我想通过<app-root>在 index.html 中嵌入元素来使用路由等初始化完整的应用程序——这是AppComponent. 另一方面,在某些页面上,不应该初始化完整的应用程序,而应该只初始化一个<header-search>我使用 @angular/elements(Web 组件)注册的特定组件。这也意味着在这种情况下,除了<header-search>初始化(如果它不是由<header-search>组件本身嵌入)之外,不应该发生路由,也不应该发生任何其他组件。

旁注只是为了让您了解用例的背景:在我正在构建的项目中,并非所有部分都与 Angular 解耦。一些页面使用 Twig/PHP 在后端呈现。但是我需要使用 Angular 构建的标题中的搜索功能也可以在这些页面上使用。这意味着我不会同时拥有完整的应用程序,只有HeaderSearchComponent在这种情况下。然而,在其他页面上,完整的应用程序将被初始化,包括HeaderSearchComponet,因此不需要使用 Web 组件单独嵌入 - 在这种情况下, <app-root>元素就足够了。

我的想法在哪里使用角度元素将HeaderSearchComponent作为<header-search>自定义 Web 组件注册,例如:

@NgModule({
  imports: [BrowserModule, FormsModule, SharedModule],
  declarations: [AppComponent],
  bootstrap: [AppComponent],
  entryComponents: [HeaderSearchComponent]
})
export class AppModule implements DoBootstrap {
  constructor(injector: Injector) {
    const webComponent = createCustomElement(HeaderSearchComponent, {
      injector
    });
    customElements.define("header-search", webComponent);
  }

  public ngDoBootstrap(): void {}
}
Run Code Online (Sandbox Code Playgroud)

随着我应该能够呈现HeaderSearchComponent使用<header-search>或完整的应用程序中使用<app-root>。但是,一旦我只嵌入<header-search>而没有同时<app-root>可用,Angular 就会抛出一个错误:

错误:选择器“app-root”不匹配任何元素

您可以在以下最低Stackblitz例如尝试了这一点自己无需进行复杂的应用程序逻辑和路由,通过更换<app-root></app-root><header-search></header-search>index.html文件。

https://stackblitz.com/edit/angular-ivy-a4ulcc?file=src/index.html

如前所述,我需要的是一个<header-search><app-root>存在元素的工作组件。而且,应该可以<app-root>在没有<header-search>组件的情况下拥有完整应用程序的元素。所以它是 header-search 或 app-root,两者都应该工作。

如何将自定义元素组件(在本例中<header-search>)作为入口点,并且仍然可以使用该<app-root>元素初始化完整的 Angular 应用程序?

dud*_*ude 5

Angular Web Components 已经可以使用 Angular 元素了。到目前为止,我遇到的问题是我不能同时拥有一个没有<app-root>元素的 Web 组件。但是,boostrap完全删除app 模块的属性并添加

entryComponents: [AppComponent],
Run Code Online (Sandbox Code Playgroud)

将使错误消失。但是,这将不再初始化<app-root>,因为我们已将其从boostrap部件中删除。现在我们必须有条件地手动引导应用程序:

public ngDoBootstrap(appRef: ApplicationRef): void {
  if (document.querySelector('app-root')) {
    appRef.bootstrap(AppComponent);
  }
}
Run Code Online (Sandbox Code Playgroud)

这将解决问题。