typescript 将组件作为“参数”传递给 Angular 2 中的另一个组件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/34575897/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-21 03:11:27  来源:igfitidea点击:

Passing a component as an 'argument' to another component in Angular 2

typescriptangular

提问by AstrOne

I am new to web development and I have just started building an Angular 2 app. At this point I am trying to create some CRUD components/forms but I find my self duplicating a lot of code. I am not going to ask what are the common best practices to avoid code duplication and achieve component reusability when designing CRUD applications with Angular2, because the post will get locked. I will rather focus on one particular aspect:

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

I have a "CRUD page" that has a list (it is an html table actually) of resources and several buttons that open up "create", "read", and "edit" forms. The list is a separate component on its own and the create/read/edit separate components as well. Each row of the table includes another component which knows how to render a resource item. I will call this <resource-item>component. However, I have several of those "CRUD pages", each page for a different resource. So what I want is to reuse the list component for all the resources. So the first thing to do is to add Inputs or Attributes to the list component in order to control its labels. So far so good.

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

But what about the <resource-item>component? Each resource of my application might have a completely different structure. As a result I will need different components for different resources, e.g.: <resource-a-item>, <resource-b-item>, etc. How can I specify which resource item component I want to use every time I create a list component?

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

Thank you for your time.

感谢您的时间。

回答by toskv

This seems to be a perfect fit for content transclusion.

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

Angular 2 comes with a component called ng-contentthat allows you to insert external html/components as the content of your component.

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

You just need to use in the place where you want the content to be displayed in your component.

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

For example:

例如:

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() {

  }
}

And you can specify the content you want injected from the component's parent this way:

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

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'
  }
}

You can see working example here.

您可以在此处查看工作示例。

In your case you can make the list row/item a component that can accept some content to display.

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

回答by Sasxa

I'm working on reusable component scenario that might be of use to you. In this example it's configuratorcomponent that has a basic structure and it's used to configure other components via valuesobject (comes from form.values).

我正在研究可能对您有用的可重用组件方案。在此示例中,它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);
  }
}

I use it in a hostcomponent as a sibling of component it configures.

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

@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');
}

The resource component could be:

资源组件可以是:

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

This is the service I'm using to communicate between sibling components:

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

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];
  }
}

EDIT:This might be 'overkill' for your use case (: I just saw other answers, both valid for simpler scenarios... I like to keep things separate as much as possible, so each component does one thing. I've been looking into ways to communicate between reusable components and this solution is something that works nicely. Thought it could be useful to share (;

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

回答by Günter Z?chbauer

You can use ngSwitch (ng-switch in Angular2) if the list of differentresource-x-item>is fixed. You can also use routing to add components dynamically. If the above don't work for your use case you can use, DynamicComponentLoader` (How to use angular2 DynamicComponentLoader in ES6?)

如果不同的列表是固定的,您可以使用 ngSwitch(Angular2 中的ng-switchresource-x-item>。您还可以使用路由来动态添加组件。如果以上对您的用例不起作用,您可以使用 DynamicComponentLoader`(如何在 ES6 中使用 angular2 DynamicComponentLoader?