web-dev-qa-db-ja.com

ジェネリック型でコンポーネントを宣言する

Angular 4?のジェネリック型でコンポーネントを宣言することは可能ですか?

次のコードはビルドエラーの原因になります。

_export class MyGenericComponent<T> implements OnInit {
    @Input()  data: BehaviorSubject<T[]>;

    //...
}
_

_ng serve_の実行時のエラーは次のとおりです。

_ERROR in C:/.../my-generic.module.ts (5,10): Module '"C:/.../my-generic.component"' has no exported member 'MyGenericComponent'.
_

例:

次の例は、@Input() dataが1つのコンポーネントを「このコンポーネントを呼び出す」から別のコンポーネントに変更する一般的なデータテーブルを実装する試みです。質問は、_BehaviorSubject<any[]>_を_BehaviorSubject<T[]>_に変更できますか?Tはコンポーネントに渡されるジェネリック型ですか?

_@Component({
  selector: 'my-data-list',
  templateUrl: './data-list.component.html',
  styleUrls: ['./data-list.component.css']
})
export class DataListComponent implements OnInit {
  @Input()  data: BehaviorSubject<any[]>;
  @Output() onLoaded = new EventEmitter<boolean>();

  private tableDataBase : TableDataBase = new TableDataBase();
  private dataSource : TableDataSource | null;

  constructor() { }

  ngOnInit() {
    this.tableDataBase.dataChange = this.data;
    this.dataSource = new TableDataSource(this.tableDataBase);
    this.onLoaded.emit(true);
  }
}

class TableDataBase {
  dataChange: BehaviorSubject<any[]> = new BehaviorSubject<any[]>([]);

  get data(): any[] {
    return this.dataChange.value;
  }
}

class TableDataSource extends DataSource<any> {

  constructor(private tableDataBase: TableDataBase) {
    super();
  }

  connect(): Observable<any[]> {
    return Observable.of(this.tableDataBase.data);
  }

  disconnect() {}
}
_
18
Strider

次のように、ViewChildを介してTypeパラメーターにアクセスすることもできます。

export class Bazz {
  name: string;

  constructor(name: string) {
    this.name = name;   
  }
}

@Component({
  selector: 'app-foo',
  template: `<div>{{bazz?.name}}</div>`,
  exportAs: 'appFoo'
})
export class FooComponent<T> {
  constructor() {}
  private _bazz: T;

  set bazz(b: T) {
    this._bazz = b;
  }

  get bazz(): T {
   return this._bazz;
  }
}

@Component({
  selector: 'app-bar',
  template: `<app-foo #appFoo></app-foo>`,
  styleUrls: ['./foo.component.scss'],
})
export class BarComponent<T> implements OnInit {
  @ViewChild('appFoo') appFoo: FooComponent<Bazz>;

  constructor() {}

  ngOnInit() {
    this.appFoo.bazz = new Bazz('bizzle');
    console.log(this.appFoo.bazz);
  }
}
13
Matt Ringer

宣言できますが、直接使用することはできません。次のようなことができます:

export abstract class Form<T> implements OnInit, OnChanges {
  someMethod() { throw 'Dont use directly' }
  otherMethod() { return 'Works!'; }
  // Note that below will cause compilation error
  //   TypeError: Object prototype may only be an Object or null: undefined
  // You cannot use protected in this usecase
  protected anotherMethod() { }
}

@Component({})
export class ModelOneForm extends Form<ModelOne> {
  someMethod() { return this.otherMethod(); }
}
6
Sasxa

この方法を検討できます。次のようなデータのインターフェースを作成します。

interface ListItem {
  info: string;
  ...
}

インターフェイスに準拠するようにリストするデータを変換し、ListDataComponentによって解釈できるようにします。 ListDataComponentは、インターフェイスのプロパティに従ってデータを一覧表示できます。

import { Component, OnInit, Input } from '@angular/core';

@Component({
  selector: 'data-list',
  templateUrl: './data-list.component.html',
  styleUrls: ['./data-list.component.scss']
})
export class DataListComponent implements OnInit {
    @Input() public items: ListItem[];

    constructor() {
    }

    ngOnInit() {
    }
}
0
Jun711

表示されるデータの種類ごとに複数の子コンポーネントを持つ親リストコンポーネントを作成し、[ngSwitch]および*ngSwitchCase表示するものを決定します。

@Component({
  selector: 'app-list',
  template: `
    <ng-container *ngFor="let item in list$ | async" [ngSwitch]="item.type">
      <app-list-item-one [item]="item" *ngSwitchCase="listItemType.One"></app-list-item-one>
      <app-list-item-two [item]="item" *ngSwitchCase="listItemType.Two"></app-list-item-two>
    </ng-container>
  `
})
export class ListComponent extends OnInit {
  list$: Observable<ListItem[]>

  constructor(
    private listApi: ListApiService
  ) { }

  ngOnInit() {
    this.list$ = this.listApi.getList(...)
  }
}

@Component({
  selector: 'app-list-item-one',
  template: `
    {{ item.aProperty }}
  `
})
export class ListItemOneComponent {
  @Input() item: ListItemOne
}

@Component({
  selector: 'app-list-item-two',
  template: `
    {{ item.bProperty }}
  `
})
export class ListItemTwoComponent {
  @Input() item: ListItemTwo
}

export class ListItem {
  id: string
}

export class ListItemOne {
  aProperty: string
}

export class ListItemTwo {
  bProperty: string
}

0
Trevor