【问题标题】:Passing a component as an 'argument' to another component in Angular 2将组件作为“参数”传递给Angular 2中的另一个组件
【发布时间】:2016-04-07 03:58:03
【问题描述】:

我是 Web 开发的新手,我刚刚开始构建 Angular 2 应用程序。此时我正在尝试创建一些 CRUD 组件/表单,但我发现我自己复制了很多代码。我不会问在使用 Angular2 设计 CRUD 应用程序时避免代码重复和实现组件可重用性的常见最佳实践是什么,因为帖子会被锁定。我宁愿专注于一个特定方面:

我有一个“CRUD 页面”,它有一个资源列表(实际上是一个 html 表)和几个打开“创建”、“读取”和“编辑”表单的按钮。该列表本身是一个单独的组件,并且创建/读取/编辑单独的组件也是如此。表格的每一行都包含另一个知道如何呈现资源项的组件。我将其称为<resource-item> 组件。但是,我有几个“CRUD 页面”,每个页面用于不同的资源。所以我想要的是为所有资源重用列表组件。所以要做的第一件事就是将 Inputs 或 Attributes 添加到列表组件中,以控制其标签。到目前为止,一切都很好。

但是<resource-item> 组件呢?我的应用程序的每个资源可能具有完全不同的结构。因此,对于不同的资源,我需要不同的组件,例如:<resource-a-item><resource-b-item> 等。如何指定每次创建列表组件时要使用的资源项组件?

感谢您的宝贵时间。

【问题讨论】:

    标签: typescript angular


    【解决方案1】:

    如果不同resource-x-item> 的列表是固定的,您可以使用 ngSwitch (ng-switch in Angular2)。 您还可以使用路由来动态添加组件。 如果上述方法不适用于您的用例,您可以使用 DynamicComponentLoader` (How to use angular2 DynamicComponentLoader in ES6?)

    【讨论】:

      【解决方案2】:

      这似乎非常适合内容嵌入。

      Angular 2 带有一个名为 ng-content 的组件,它允许您插入外部 html/组件作为组件的内容。

      您只需要在您希望内容显示在组件中的位置使用

      例如:

      import {Component} from 'angular2/core'
      
      @Component({
        selector: 'holder',
        providers: [],
        template: `
          <div>
            <h2> Here's the content I got </h2>
            <ng-content></ng-content>
          </div>
        `,
        directives: []
      })
      export class Holder {
        constructor() {
      
        }
      }
      

      您可以通过这种方式指定要从组件的父级注入的内容:

      import {Component} from 'angular2/core';
      import {Holder} from './holder';
      
      @Component({
        selector: 'my-app',
        providers: [],
        template: `
          <div>
            <h2>Hello {{name}}</h2>
            <holder>
              <div>yeey transcluded content {{name}}</div>
            </holder>
          </div>
        `,
        directives: [Holder]
      })
      export class App {
        constructor() {
          this.name = 'Angular2'
        }
      }
      

      您可以查看工作示例here

      在您的情况下,您可以使列表行/项目成为可以接受某些内容以显示的组件。

      【讨论】:

      • 非常感谢。 ng-content 拯救了我的一天。
      • 这个答案非常有用。谢谢。我有个问题。有一种方法可以显示另一个组件,但只显示一些列,如姓名和姓氏。?提前致谢。我不会在 SOF 中提问,因为我不会
      • @toskv 我写了一条评论寻求你的帮助。提前致谢
      • 做到这一点的方法是让你想要显示的组件是可配置的,让它有输入来显示/隐藏你需要的东西。如果您有更具体的案例,请告诉我,我很乐意提供帮助。
      【解决方案3】:

      我正在研究可能对您有用的可重用组件场景。在本例中,configurator 组件具有基本结构,用于通过values 对象(来自form.values)配置其他组件。

      import {Component, Input, EventEmitter, ViewEncapsulation} from 'angular2/core';
      
      @Component({
        encapsulation: ViewEncapsulation.None,
        selector: 'configurator',
        template: `
          <div [hidden]="!active">
            <span (click)="active = false">&times;</span>
            <h3>{{ title }}</h3>
            <form>
              <ng-content></ng-content>
            </form>
          </div>
        `
      })
      export class ConfiguratorComponent {
        @Input() title: string;
        @Input() values: any = {};
        @Input() emitter: EventEmitter<any>;
      
        public active: boolean = false;
      
        set(key: string, value?: any) {
          this.values[key] = value || !this.values[key];
          if (this.emitter)
            this.emitter.emit(this.values);
        }
      }
      

      我在 host 组件中使用它作为它配置的组件的兄弟。

      @Component({
        directives: [
          ConfiguratorComponent,
          ResourceOneComponent,
        ],
        pipes: [...],
        providers: [...],
        template: `
        <configurator title="Resource One" #cfg [values]="one.values" [emitter]="configEmitter">
      
          <label>Size:
            <input type="number" min="0" #size [value]="cfg.values.size" (change)="cfg.set('size', size.value)">
          </label>
      
        </configurator>
        <resource-one #one [emitter]="configEmitter"></resource-one>
        `
      })
      class HostComponent {
        public configEmitter = EmitterService.get('resource_one');
      }
      

      资源组件可以是:

      class ResourceOneComponent extends CRUDComponent {
        public values: { size: 5 };
        private ngOnChanges() {
          if (this.emitter) 
            this.emitter.subscribe(values => {
              // use values from configurator
            });
        }
      }
      

      这是我用来在同级组件之间进行通信的服务:

      import {Injectable, EventEmitter} from 'angular2/core';
      
      @Injectable()
      export class EmitterService {
        private static _emitters: { [ID: string]: EventEmitter<any> } = {};
        static get(channel: string): EventEmitter<any> {
          if (!this._emitters[channel]) 
            this._emitters[channel] = new EventEmitter();
          return this._emitters[channel];
        }
      }
      

      编辑:对于您的用例来说,这可能是“矫枉过正”(:我刚刚看到其他答案,都适用于更简单的场景......我喜欢尽可能地将事情分开,所以每个组件都做一件事。我一直在研究可重用组件之间进行通信的方法,这个解决方案效果很好。认为分享(;

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-05-31
        • 2017-11-29
        相关资源
        最近更新 更多