Как бы вы отображали рекурсивные данные в таблице с angular2?

У меня есть рекурсивная структура данных (рекурсивная через свойство children), как показано ниже:

export interface IExecutableLog {
    round: number;
    log: string;
}

export interface IExecutableResult {
    uid: string;
    name: string;
    desc: string;
    status: string;
    passedRounds: number;
    totalRound: number;
    children?: IExecutableResult[];
    statementType?: string;
    logs?: IExecutableLog[];
}

export interface ISummary {
    title: string;
    jobName: string;
    timestamp: Date;
    tester: string;
    result: string;
    executionId: string;
    testJobId: string;
    resultDetails: IExecutableResult;
}

И я хочу отображать данные типа Isummary из бэкэнда.

Я попытался определить компонент, как показано ниже:

// pats-report-element.component.ts
import { Component, Input, ViewEncapsulation } from '@angular/core';
import { IExecutableResult } from '../pats-report.interface';

@Component({
    selector: 'pats-report-element',
    templateUrl: 'app/report/basic/pats-report-element.html',
    encapsulation: ViewEncapsulation.None,
})
export class  PatsReportElementComponent {
    @Input()
    public data: IExecutableResult;
}
// app/report/basic/pats-report-element.html
<tr>
    <td>{{data?.name}}</td>
    <td>{{data?.status}}</td>
    <td>{{data?.rounds}}</td>
    <td>{{data?.passedRounds}}</td>
    <td>{{data?.rounds > 0 ? (data.passedRounds / data.rounds) * 100 + "%" : "NA"}}</td>
    <td>{{data?.timestamp | date:"y-MM-dd HH:mm:ss"}}</td>
</tr>

<template [ngIf]="data && data.children">
    <template ngFor let-item [ngForOf]="data.children" let-i="index">
        <pats-report-element [data]="item"></pats-report-element>
    </template>
</template>

Но визуализированный DOM будет включать элемент хоста 'pats-report-element', который недействителен внутри <table></table>tag. DOM выглядит следующим образом: введите здесь описание изображения

Я проверил документ angular2 и, похоже, attribute-directives является правильный выбор. Но я не могу найти способ использовать шаблон с директивами атрибутов так же, как я делаю в PatsReportElementComponent.

Каков правильный способ достижения моей цели?

[Обновление 1]

Попробовал предложение @Günter Zöchbauer, но все еще не решил мою проблему. Визуализированный DOM все еще не такой, как ожидалось (<tr></tr> все еще не сглажен).

введите здесь описание изображения


person ricky    schedule 24.08.2016    source источник
comment
Похоже на stackoverflow.com/questions/37746516/use- компонент-в-себе/ и stackoverflow.com/questions/38716105/   -  person Günter Zöchbauer    schedule 24.08.2016
comment
Я не думаю, что есть способ сделать это. Я думаю, вам нужно сгладить данные, а затем выполнить *ngFor над сглаженными данными.   -  person Günter Zöchbauer    schedule 25.08.2016
comment
@GünterZöchbauer Да, похоже, это действительно не работает ... не очень приятно. Выравнивание данных перед их предоставлением пользователю может сделать приложение довольно медленным, когда извлекаются большие данные.   -  person PeMa    schedule 26.04.2018


Ответы (4)


Вы можете использовать селектор атрибутов

@Component({
  selector: '[pats-report-element]',

то вы можете добавить свой элемент, например

<tr pats-report-element [data]="item"></tr>

Невозможно получить элемент, отображаемый без его селектора.

person Günter Zöchbauer    schedule 24.08.2016
comment
Спасибо за Ваш ответ! Можем ли мы использовать селектор атрибутов с @Component? Я видел только использование селектора атрибутов с @Directive. Не подскажете, где документ? Я обновил свой код в соответствии с вашим ответом, но есть исключение: `Ошибки синтаксического анализа шаблона: невозможно привязать к «данным», поскольку это не известное свойство «pats-report-element». 1. Если «pats-report-element» является компонентом Angular и имеет вход «data», убедитесь, что он является частью этого модуля. ...` - person ricky; 24.08.2016
comment
То же самое работает с @Component(). Компонент является директивой ;-) только с дополнительным представлением. - person Günter Zöchbauer; 24.08.2016
comment
Получил исключение: zone.js: 461 Отклонение необработанного обещания: ошибки синтаксического анализа шаблона: невозможно выполнить привязку к «данным», поскольку это не известное свойство «pats-report-element». 1. Если «pats-report-element» является компонентом Angular и имеет вход «data», убедитесь, что он является частью этого модуля. 2. Если 'pats-report-element' является веб-компонентом, добавьте CUSTOM_ELEMENTS_SCHEMA в '@NgModule.schema' этого компонента, чтобы скрыть это сообщение. Вы заметили что-то не так? - person ricky; 24.08.2016
comment
Исправьте исключение и попробовал ваш подход, но все равно не получил то, что хочу. Пожалуйста, смотрите мое обновление в исходном посте. Спасибо еще раз! - person ricky; 25.08.2016

После многих усилий мне все еще не удалось сделать это с помощью собственного angular2. И я остановился на сторонней библиотеке -- ag-grid- нг2. Это работает хорошо, за исключением того, что это излишество для моих требований.

person ricky    schedule 26.08.2016

Я не уверен, решит ли это вашу проблему, в компоненте, который вы рекурсивно ссылаетесь на один и тот же компонент в шаблоне, вы должны ссылаться на него в своей директиве.

// pats-report-element.component.ts import { Component, Input, ViewEncapsulation } from '@angular/core'; импортировать { IExecutableResult } из '../pats-report.interface';

@Component({
    selector: 'pats-report-element',
    directives: [forwardRef(() => PatsReportElementComponent )], // <<<<<< change
    templateUrl: 'app/report/basic/pats-report-element.html',
    encapsulation: ViewEncapsulation.None,
})
export class  PatsReportElementComponent {
    @Input()
    public data: IExecutableResult;
}
// app/report/basic/pats-report-element.html
<tr>
    <td>{{data?.name}}</td>
    <td>{{data?.status}}</td>
    <td>{{data?.rounds}}</td>
    <td>{{data?.passedRounds}}</td>
    <td>{{data?.rounds > 0 ? (data.passedRounds / data.rounds) * 100 + "%" : "NA"}}</td>
    <td>{{data?.timestamp | date:"y-MM-dd HH:mm:ss"}}</td>
</tr>

<template [ngIf]="data && data.children">
    <template ngFor let-item [ngForOf]="data.children" let-i="index">
        <pats-report-element [data]="item"></pats-report-element>
    </template>
</template>

Посмотрите, работает ли это для вас.

person Savaratkar    schedule 26.08.2016

Рекурсивные таблицы

Вы можете поместить еще один <table> для дочерних элементов уровня внутри <my-component-selector>. Просто сделайте это после закрытия тега таблицы текущего уровня:

<table>
    <tbody>
        <tr>
            <td>{{level.id}}</td>
            <td>{{level.title}}</td>
        </tr>
    </tbody>
</table>
<div *ngFor="let item of level.childLevels">
    <my-component-selector [level]="item">
         <!-- Here will be inserted another instance of this HTML file with itself table and itself recursion -->
    </my-component-selector>
</div>

Где у вас есть компонент для каждого уровня иерархии, например:

@Component({
    selector: 'my-component-selector',
    templateUrl: './my-recursive.component.html'
})
export class MyRecursiveComponent implements OnInit {

    @Input() level: LevelItem;

    onInit() {
        if (!level) {
             loadRootLevelByNetwork();
        }
    }

}

Здесь переменная level устанавливается из внешнего компонента с помощью [level]="item" в HTML или загружается по сети (для корневого компонента).

person Evgeny Nozdrev    schedule 11.09.2020