角组件继承和继承订阅

时间:2020-06-17 08:24:46

标签: angular inheritance publish-subscribe subscription

下面是一个组件,我将在其他各种组件中进行扩展,以便重用一些代码。

import { Component } from '@angular/core';

@Component ({
   selector: 'my-app',
   template: ` <div>
      <h1>{{appTitle}}</h1>
      <div>To Tutorials Point</div>
   </div> `,
})

export class AppComponent {
   appTitle: string = 'Welcome';
   ngOnInit(){
      this.registerSomeSubscriptions();
   }
   registerSomeSubscriptions(){
      this.subscribeSomething.subscribe((data)=>{
         performSomeAction();
      })
   }


}

我可以像下面这样扩展它

 import { Component } from '@angular/core';

@Component ({
   selector: 'my-app',
   template: ` <div>
      <h1>{{appTitle}}</h1>
      <div>To Tutorials Point</div>
   </div> `,
})

export class ChildComponent extends AppComponent {
   
}

虽然我知道该组件的公共成员将在子组件中可用。

我的问题

  1. 对于这两个组件,我仍然需要使用单独的html文件吗?还是某些代码风格或问题解决技术可以通过我不知道的某些技术来重用同一html模板以及特定于孩子的特定实现。

5 个答案:

答案 0 :(得分:2)

子组件可以使用与父组件相同的html模板,也可以拥有自己的html文件,在这种情况下,将不使用父组件的html。

如果要在子组件中使用父组件的html并进行一些修改,则可以重用父组件而不是继承它。

  • 使您的父组件成为可重复使用的组件
  • 在子/功能组件的模板中,使用其选择器添加父组件
    // add something specific to child/feature component here
    <app-reusable-component></app-reusable-component>
    // add something specific to child/feature component here

可重用组件的html以及在功能组件的html中添加的其他html都将可用。

  • 使用组件交互-InputOutput在可重用组件和功能组件之间传递数据。

  • Input-通过输入绑定将数据从要素组件传递到可重用组件

reusable-component.ts:
export class ReusableComponent implements OnInit {
   @Input() dataIn: Observable<object>;
   ngOnInit() {
     dataIn.subscribe(data => {
       // display data
     });
   }
}

feature-component.html:
...
<app-reusable-component [dataIn]="dataToDisplay$"></app-reusable-component>
...

feature-component.ts:
export class FeatureComponent implements OnInit {
  public dataToDisplay$: Observable<object>;
  ngOnInit() {
    this.dataToDisplay$ = this.http.get(url);
  }
}
  • Output-将数据/事件从可重用组件发送到功能组件
reusable-component.ts:
export class ReusableComponent implements OnInit {
   @Input() dataIn: Observable<object>;
   @Output() eventOut: EventEmitter<object> = new EventEmitter<object>();
   ngOnInit() {
     dataIn.subscribe(data => {
       // display data
     });
   }
   userInput(value) {
      this.eventOut.emit(value);
   }
}

feature-component.html:
...
<app-reusable-component [dataIn]="dataToDisplay$" (eventOut) ="handleUserData($event)"></app-reusable-component>
...

feature-component.ts:
export class FeatureComponent implements OnInit {
  public dataToDisplay$: Observable<object>;
  ngOnInit() {
    this.dataToDisplay$ = this.http.get(url);
  }
  handleUserData(value) {
    this.http.post(url, value);
  }
}

通过这种方法,您可以在所有子/功能组件中重复使用父组件的模板,并且可以在子/功能组件中添加其他html内容,并在它们之间传递数据。

答案 1 :(得分:1)

如果只想将相同的模板用于子组件和父组件,则只需将该模板放入html文件中,并使用templateUrl进行引用。您的订阅将被继承,并且您将能够从子组件访问受保护的公共变量和受保护变量。

现在,如果您想继承父模板但又能够进行模板修改,这会有点困难,因为angular不提供模板继承。

一种可能的替代方法是使用模板引擎生成html。在我们的一个项目中,我们使用nunjucks来解决此限制。

因此,基本上,您可以使用nunjucks模板指定父组件的html

parent.component.html.njk

<div>

Parent template

{% block specific %}
{% endblock %}

</div>

parent.component.ts

@Component ({
   selector: 'app-parent',
   templateUrl: `parent.component.html`, //Reference compiled template (not .njk)
})
export class ParentComponent
{
    //...
    

然后,您还将子组件定义为从父模板继承的nunjucks模板

child.component.html.njk

{% extends '/path/to/parent/parent.component.html.njk' %}

{% block specific %}
  Child content: {{childContent}}
{%endblock %}

child.component.ts

@Component ({
   selector: 'app-child',
   templateUrl: `child.component.html`, //reference .html, not .njk
})
export class ChildComponent extends ParentComponent
{
  public childContent = "hello";

  //Access to public/protected members and methods from parent componenent
   
  

最重要的是,我们有一个基本的监视脚本,该脚本监视.njk文件的更改并生成相应的html

watch.js

const nunjucks = require('nunjucks');

//Nunjuck config to use <$ and $> for tags, instead of {{ and }}, to avoid conflicting with angular
const nunjucksEnv = nunjucks.configure(
  {
    noCache: true,

    tags:
      {
        variableStart: '<$',
        variableEnd: '$>',
      }
  }
);

//Add watch loop here. Whenever a njk file changes, call the code below
nunjucks.render(njkTemplateFileThatJustChanged, {}, function (err, html)
{
  if (!err)
  {
    let compiledPath = njkTemplateFileThatJustChanged.replace('.njk', '');
    fs.writeFileSync(compiledPath, html);
  }
}

答案 2 :(得分:0)

如果模板在文件中,则可以重复使用它。 @Component是装饰器,它为“组件”分配一些“元”数据,因此您不会从扩展类继承它。如果模板在单独的文件中,则可以在@Component装饰器的Select-Xml -Xml $Scans -XPath "//ValidatedOnline" | % node #text ----- true 属性中使用它。

答案 3 :(得分:0)

您可能无法扩展html,但是可以通过多种方式使用模板:

  1. 在服务中设置基本模板的TemplateRef,并使用directive在以后的任何地方使用它。

    A:的缺点是,基本组件需要手动实例化,并且在内存中直到容器可见为止。 [请参阅示例-BaseOneComponent]

    B。如果模板没有太多绑定,则可以在根(AppComponent)本身中对其进行初始化。

  2. 为占位符BaseTwoComponent创建公用组件,并使用<ng-content>从使用者组件[DerivedTwoComponent]投影数据。您还可以为<ng-content>创建多个占位符,并将它们与选择器一起使用。 选中此Angular Content Projection Guide,了解如何使用多个插槽进行内容投影。

Stackblitz:Template extension

答案 4 :(得分:0)

https://plnkr.co/edit/HNG0ndIErlOfVnMl?preview

刚刚在子组件模板中使用了父组件的选择器。检查我在app.ts中添加的代码。