【问题标题】:Using component both as custom element and as angular component将组件用作自定义元素和角度组件
【发布时间】:2018-06-11 15:57:38
【问题描述】:

我正在尝试将 Angular 组件用作自定义元素,以便我可以动态地将其添加到 DOM 并自动引导,但我还需要将此组件作为另一个组件模板的一部分。

我已将 Description 组件注册为自定义元素,并且只要我将以下内容添加到 dom,它就会正确引导:

<app-description text="Some description text..."></app-description>

但是,如果我想将该组件用作 Header 组件模板的一部分(该模板具有正确设置的属性 descriptionText),则不会显示任何描述。我是这样使用它的:

<app-description text="{{descriptionText}}"></app-description>

我也试过了:

<app-description [text]="descriptionText"></app-description>

<app-description text="descriptionText"></app-description>

但无论如何我都没有得到预期的结果。

所以,我的问题是: 有没有办法将 Angular 组件定义为自定义元素,并且还能够将其包含在任何 Angular 组件的模板中?

编辑: 我在 Header 和 Description 组件的 ngOnInit 方法中放置了一个 console.log() ,我在控制台中打印了这个:

似乎组件被初始化了两次,第二次'text'设置为未定义?

描述组件:

@Component({
  selector: 'app-description',
  templateUrl: './description.component.html',
  styleUrls: ['./description.component.css']
})
export class DescriptionComponent implements OnInit {
  @Input() text: String;

  constructor() {}

  ngOnInit() {
    console.log('text:', this.text)
  }
}

描述模板:

<div class="description">
    <h3>{{ text }}</h3>
</div>

头组件:

  @Component({
    selector: 'app-header',
    templateUrl: './header.component.html',
    styleUrls: ['./header.component.less']
  })
  export class HeaderComponent implements OnInit {
    @Input() title: String;
    @Input() subtitle: String;
    @Input() descriptionText: String;

    constructor() {}

    ngOnInit() {
      console.log('descriptionText:', this.descriptionText)
    }
  }

页眉模板:

<div class="header flex-container">
    <h1>{{ title }}</h1>
    <h2>{{ subtitle }}</h2>
    {{descriptionText}} <!-- shown correctly! -->
    <app-description text="{{descriptionText}}"></app-description>
</div>

模块:

@NgModule({
  declarations: [
    AppComponent,
    HeaderComponent,
    DescriptionComponent
  ],
  imports: [
    BrowserModule,
    FormsModule
  ],
  providers: [],
  bootstrap: [],
  entryComponents: [
    AppComponent,
    HeaderComponent,
    DescriptionComponent
  ],
  schemas : [
    CUSTOM_ELEMENTS_SCHEMA
  ]
}) 

export class AppModule {
  constructor(private injector: Injector) {
    this.registerCustomElements();
  }

  ngDoBootstrap() {}

  registerCustomElements() {
    const HeaderElement = createCustomElement(HeaderComponent, {injector: this.injector});
    customElements.define('app-header', HeaderElement);

    const DescriptionElement = createCustomElement(DescriptionComponent, {injector: this.injector});
    customElements.define('app-description', DescriptionElement);
  }
}

我正在使用 Angular 6 中提供的 Angular 自定义元素

谢谢!

【问题讨论】:

  • 所有你应该工作的东西(除了最后一个;那是文字“descriptionText”而不是变量。你有任何控制台错误吗?
  • 感谢您的回答,布拉德利。我没有收到任何控制台错误,但我看到的是属性“文本”没有被传递给组件。
  • @BradleyDotNET 请查看我的编辑,我添加了更多信息。谢谢!
  • 两次初始化很奇怪;您能否在 GitHub 上发布更多代码甚至链接到工作示例?
  • @BradleyDotNET 我在编辑中添加了一些代码!

标签: angular web-component angular6 custom-element


【解决方案1】:

好的,我使用以下代码解决了问题,问题与嵌套 css 代码相关,然后您需要在您的子自定义元素(在本例中为 &lt;app-description&gt;)中放入以下行 encapsulation: ViewEncapsulation.None,然后我更改了var descriptionTestdescription

description.component.ts

@Component({
  selector: 'app-description',
  templateUrl: './description.component.html',
  styleUrls: ['./description.component.css'],
  encapsulation: ViewEncapsulation.None
})

description.component.html

<div>
    {{text}}
</div>

header.component.ts

  @Input() title: String;
  @Input() subtitle: String;
  @Input() description: String;

header.component.html

    <div class="header flex-container">
      <h1>{{ title }}</h1>
      <h2>{{ subtitle }}</h2>
      {{description}} <!-- shown correctly! -->
      <app-description text="{{description}}"></app-description>
    </div>

**App.module.ts**

@NgModule({
  declarations: [
    AppComponent,      
    HeaderComponent,
    DescriptionComponent  
  ],
  imports: [
    BrowserModule,    
  ],  
  providers: [],
  entryComponents:[
    HeaderComponent,
    DescriptionComponent
  ],
  bootstrap: []
})
export class AppModule {
  constructor(private injector: Injector) {

  }

  ngDoBootstrap() {
    this.registerCustomElements();
  }

  registerCustomElements() {
    const DescriptionElement = createCustomElement(DescriptionComponent, {injector: this.injector});
    customElements.define('app-description', DescriptionElement);

    const HeaderElement = createCustomElement(HeaderComponent, {injector: this.injector});
    customElements.define('app-header', HeaderElement);       
  }

Index.html

 <app-root>
  </app-root>
  <app-description text="'HOLA!'"></app-description>

  <app-header title="Title"
      subtitle="Subtitle"
      description="DESCRIPTION"
  ></app-header>

src

github repository 这个例子

【讨论】:

  • 谢谢你,亚伯!!您是否像我在代码中那样将组件注册为自定义元素?你在 Angular 6 下吗?今天我按照另一位用户的建议尝试这样做,但没有解决问题。
  • 是的,即使我使用的是相同的代码模块、组件等。只是 app.component 中的调用被 descriptionText 更改为 description-text
  • 看看我做的这个demo stackblitz
  • Abel,我无法将 添加到 index.html 并在您的演示中显示。
  • 转到您的 index.html 文件并添加以下内容:&lt;app-description text="Hello!"&gt;&lt;/app-description&gt;&lt;my-app&gt; 标记之后。是渲染描述组件吗?
【解决方案2】:

我找到了解决办法!

如果我们看到我的 description.component.ts 这个组件的 HTML 标签是 app-description:

@Component({
  selector: 'app-description',
  ...

在我的 app.module.ts 中,我将 DescriptionComponent 注册为像这样的角度元素:

const DescriptionElement = createCustomElement(DescriptionComponent, {injector: this.injector});
customElements.define('app-description', DescriptionElement);

请注意,我声明的元素与组件具有相同的标签。 我将其更改为:

const DescriptionElement = createCustomElement(DescriptionComponent, {injector: this.injector});
customElements.define('app-descriptions', DescriptionElement);

现在我可以在任何 HTML 文件中使用自定义元素,如下所示:

<body>
  <app-descriptions text="Probando 1"></app-descriptions>
</body>

并在我的 Header 模板中使用 DescriptionComponent,例如:

 <app-description text="{{descriptionText}}"></app-description>

我的结论是:使用与组件的 HTML 标记不同的 HTML 标记来声明您的 Angular Element。

感谢所有合作的人!

【讨论】:

  • 是的,很明显,角度指令应该是唯一的,以便区分,我不知道问题出在哪里,很高兴听到你解决了你的问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-08-08
  • 2021-01-15
  • 2017-01-23
  • 1970-01-01
  • 1970-01-01
  • 2021-07-05
  • 2016-12-29
相关资源
最近更新 更多