Создание абстрактного компонента для перебора списка - PullRequest
1 голос
/ 19 октября 2019

У меня есть несколько компонентов, которые выглядят так:

import { Component, Input, Output } from '@angular/core';
import { Subject } from 'rxjs';
import { Tag } from 'src/app/models';

@Component({
  selector: 'app-tag-list',
  templateUrl: './tag-list.component.html',
  styleUrls: ['./tag-list.component.scss'],
})
export class TagListComponent  {
  @Input() public tagList: Tag[];

  @Input() public displayLabel = true;
  @Input() public linkActivated = true;

  @Output() public tagClicked = new Subject<Tag>();

  constructor() {}

  public onTagClick(tag: Tag): void {
    this.tagClicked.next(tag);
  }
}
<span *ngIf="displayLabel">
  {{ "tag.tags" | translate }}
  {{ "punctuation.doublePoints" | translate }}
</span>

<ul class="list-no-style">
  <li *ngFor="let tag of tagList" (click)="onTagClick(tag)">
    <a
      *ngIf="linkActivated; else noLink"
      class="list-element link-no-style"
      [routerLink]="['/tag/' + tag.urlName]"
    >
      {{ tag.label }}
    </a>

    <ng-template #noLink>
      <span class="list-element">
        {{ tag.label }}
      </span>
    </ng-template>
  </li>
</ul>

Единственное различие между этими компонентами - это отображаемый объект, например, это может быть Artist вместо Tag.

Итак, я хочу написать компонент (скажем, AbstractListComponent), который может перебирать список и позволять мне отображать содержимое через родительский элемент, например ng-content.

Так что мой шаблон TagListComponent может выглядеть примерно так:

<abstract-list
  [dataSource]="tagList"
  [routerLinkString]="tag"
  [linkActivated]="linkActivated"
  [displayLabel]="displayLabel"
  (elementClicked)="onTagClick($e)"
>
  <ng-container *cellDef="let tag">
    {{ tag.label }}
  </ng-container>
</abstract-list>

Итак, идея состоит в том, чтобы создать пользовательский компонент MatTable, но я понятия не имел, как написать AbstractListComponent для достижения чего-то подобного.

Ответы [ 2 ]

0 голосов
/ 20 октября 2019

Мне наконец-то удалось это сделать:

element-list.component.ts

import {
  Component,
  ContentChild,
  Input,
  Output,
  TemplateRef,
} from '@angular/core';
import { Subject } from 'rxjs';

@Component({
  selector: 'element-list',
  templateUrl: './element-list.component.html',
  styleUrls: ['./element-list.component.scss'],
})
export class ElementListComponent {
  @Input() public data: any;

  @Input() public displayLabel = true;
  @Input() public linkActivated = true;

  @Input() public routerLinkString = '';

  @Output() public elementClicked = new Subject<any>();

  @ContentChild('elementContent', { static: true })
  public elementContentTemplate: TemplateRef<any>;

  public onElementClick(element: any): void {
    this.elementClicked.next(element);
  }
}

element-list.component.html

<span *ngIf="displayLabel">
  <ng-content select=".label"></ng-content>
  {{ "punctuation.doublePoints" | translate }}
</span>

<ul class="list-no-style">
  <li *ngFor="let element of data" (click)="onElementClick(element)">
    <a
      *ngIf="linkActivated; else noLink"
      class="list-element link-no-style"
      [routerLink]="['/' + routerLinkString + '/' + element.urlName]"
    >
      <ng-container
        *ngTemplateOutlet="
          elementContentTemplate;
          context: { $implicit: element }
        "
      >
      </ng-container>
    </a>

    <ng-template #noLink>
      <span class="list-element">
        <ng-container
          *ngTemplateOutlet="
            elementContentTemplate;
            context: { $implicit: element }
          "
        >
        </ng-container>
      </span>
    </ng-template>
  </li>
</ul>

tag-list.component.html

<element-list
  [data]="tagList"
  [linkActivated]="linkActivated"
  [displayLabel]="displayLabel"
  [routerLinkString]="'tag'"
  (elementClicked)="onTagClick($event)"
>
  <span class="label">
    {{ "tag.tags" | translate }}
  </span>

  <ng-template #elementContent let-tag>
    {{ tag.label }}
  </ng-template>
</element-list>
0 голосов
/ 19 октября 2019

Я думаю, у вас есть хороший вариант использования для ngSwitch здесь. если вы добавите параметр objectType к своему объекту, вы можете сделать что-то, как показано ниже

<ng-container [ngSwitch]="yourObject.objectType">
  <ng-container *ngSwitchCase="'tag'">
    <ng-container *cellDef="let tag">
      {{ tag.label }}
    </ng-container>
  </ng-container>
  <ng-container *ngSwitchCase="'artist'">
    The famous: {{artist.name}}
  </ng-container>
  <ng-container *ngSwitchDefault>
    Default type
  </ng-container>
</ng-container>
...