【问题标题】:Angular component Inheritance and inheriting subscriptionsAngular 组件继承和继承订阅
【发布时间】:2020-10-07 00:18:29
【问题描述】:

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

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 模板以及通过一些我不知道的技术实现的一些子特定实现。李>

【问题讨论】:

  • 您可以使用指令来设置订阅吗...指令可以使用 Host angular.io/api/core/Host 访问主机组件上的方法/值
  • 您到底想要什么?如果你只是想重复使用相同的模板,你可以把它放在一个 html 文件中并从你的子组件中引用它
  • @David 不重用,可能是我走得太远了,但是当我们谈论继承时,我们的意思是扩展一些现有的功能,我们可以在 ts 文件中扩展组件,但是单独的 html子组件需要文件,我要问的是,如果该子 html 只是父组件 html 的扩展,但我仍然必须从父组件复制 html。但是,从下面的答案和 Rnd 来看,我觉得没有什么比 html 的继承更重要,而且视图应该以角度单独引用,但它使新开发人员的代码更难理解
  • @nobalG 你想让它像模板 html 一样,还是你也想将 appTitle 等属性移动到父组件并通过子组件传递值?

标签: angular inheritance publish-subscribe subscription


【解决方案1】:

子组件可以使用与父组件相同的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 一起可用。

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

  • 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 内容并在它们之间传递数据。

【讨论】:

    【解决方案2】:

    如果您只想为子组件和父组件重用相同的模板,那么您只需将该模板放在一个 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);
      }
    }
    

    【讨论】:

      【解决方案3】:

      如果模板在文件中,您可以重复使用它。 @Component 是一个装饰器,它为“组件”分配一些“元”数据,因此您不会从扩展类继承它。如果模板在单独的文件中,您可以在@Component 装饰器的templateUrl: 属性中使用它。

      【讨论】:

        【解决方案4】:

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

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

          答:这样做的一个缺点是基础组件需要手动实例化,并且在容器出现之前将一直在内存中。 [参见示例 - BaseOneComponent]

          B.如果模板没有太多绑定,可以在根(AppComponent)本身初始化。

        2. 为占位符BaseTwoComponent 创建一个通用组件,并使用&lt;ng-content&gt; 投影来自消费者组件[DerivedTwoComponent] 的数据。您还可以为&lt;ng-content&gt; 创建多个占位符并将它们与选择器一起使用。 查看Angular Content Projection Guide,了解如何使用多个插槽进行内容投影。

        Stackblitz:Template extension

        【讨论】:

          【解决方案5】:

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

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

          【讨论】:

            猜你喜欢
            • 2015-11-17
            • 2019-07-02
            • 2018-04-20
            • 2017-08-06
            • 1970-01-01
            • 2022-12-19
            • 2017-05-24
            • 2018-03-01
            相关资源
            最近更新 更多