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

前端 未结 3 1335
夕颜
夕颜 2020-12-06 01:38

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

相关标签:
3条回答
  • 2020-12-06 02:20

    I'm working on reusable component scenario that might be of use to you. In this example it's configurator component that has a basic structure and it's used to configure other components via values object (comes from 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 host component 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 (;

    0 讨论(0)
  • 2020-12-06 02:25

    This seems to be a perfect fit for content transclusion.

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

    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.

    0 讨论(0)
  • 2020-12-06 02:35

    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?)

    0 讨论(0)
提交回复
热议问题