排序时PrimeNG turbo表模板错误

时间:2018-04-23 19:12:38

标签: angular primeng primeng-turbotable

我正在尝试使用ngTemplateOutlet在turbo表元素中注入标头模板,因为它可以在以下代码片段中看到:

<p-table [value]="cars1">
  <ng-template pTemplate="header">
    <ng-container *ngTemplateOutlet="defaultHeader"></ng-container>
  </ng-template>
  <ng-template pTemplate="body" let-rowData>
    <tr>
      <td *ngFor="let col of cols">
        {{rowData[col.field]}}
      </td>
    </tr>
  </ng-template>
</p-table>

前面提到的带有排序的标题模板可以在这里看到:

<ng-template #defaultHeader>
  <tr>
    <th *ngFor="let col of cols" [pSortableColumn]="col.field">
        {{col.header}}
        <p-sortIcon [field]="col.field"></p-sortIcon>
    </th>
  </tr>
</ng-template>

页面加载后,会抛出以下错误:

Error: StaticInjectorError(AppModule)[ScrollableView -> Table]: 
StaticInjectorError(Platform: core)[ScrollableView -> Table]: 
NullInjectorError: No provider for Table

Converting circular structure to JSON

这是一个有效的StackBlitz example

由于在ngTemplateOutlet中使用模板标题是我的用例的要求,我想请指出我在这里做错了什么?

谢谢!

2 个答案:

答案 0 :(得分:2)

我知道这是一个老问题,但我遇到了同样的问题,在任何地方都找不到任何帮助。

我发现,如果将'Table'类添加到包装器组件的提供程序中,该错误将消失。但是然后,我还需要DomHandler,ObjectUtils和TableService的提供程序。

这使错误消失了,并允许将模板传递给包装器并传递到p表中。但是,pSortableColumn和pSelectableRow现在仅在包装器组件内的默认模板内起作用。

没有错误,因为将Table类放到包装器的提供程序列表中是给pSortableColumn和pSelectableRow一个表的新实例,以满足它们的依赖性。他们正在有效地选择和排序永远不会呈现的空表。

我通过将Table提供程序更改为useFactory来解决此问题。我的工厂函数需要包装器组件作为依赖项,然后将其子turbo表作为提供的表返回。因此,现在当pSortableColumn和pSelectableRow要求一个表时,它们会在我的包装器组件中获取正确的表。

...
import { DomHandler } from 'primeng/api';
import { Table, TableService } from 'primeng/table';
import { ObjectUtils } from 'primeng/components/utils/objectutils';
...

export function tableFactory(datalist: DataListComponent) {
  return datalist.datatable;
}

@Component({
  selector: 'app-data-list',
  templateUrl: './data-list.component.html',
  styleUrls: ['./data-list.component.scss'],
  providers: [ DomHandler, ObjectUtils, TableService, {
    provide: Table,
    useFactory: tableFactory,
    deps: [DataListComponent]
  }],
})
export class DataListComponent implements OnInit {
  @ViewChild(('datatable')) datatable: Table;
...
}

我应该提到,如果使用属性而不是ContentChildren和QueryList从父组件传递模板,则需要在包装器组件的内部定义模板,否则将再次遇到相同的问题。

例如,将模板作为属性传递给模板,并将其放在包装器内,例如 WORKS

<wrapper-component [headerTemplate]="defaultHeader">
  <ng-template #defaultHeader>
    ...
  </ng-template>
</wrapper-component>

但是像这样不起作用那样,将模板作为属性传递给模板,而不在包装器外:

<ng-template #defaultHeader>
  ...
</ng-template>
<wrapper-component [headerTemplate]="defaultHeader">
</wrapper-component>

如果您正在使用ContentChildren和QueryList,则显然需要包装器内的模板。

答案 1 :(得分:1)

这是基于 C. Witt 的回答,但已更新为更新的 Primeng(在 Angular 10.1.6 和 PrimeNG 11.3.1 上测试)。

import { Component, ContentChild, Input, TemplateRef, ViewChild } from '@angular/core';
import { Table, TableService } from 'primeng/table';

export function tableFactory(tableComponent: TableComponent) {
  return tableComponent.primengTable;
}

@Component({
  selector: 'my-table',
  templateUrl: './table.component.html',
  styleUrls: ['./table.component.scss'],
  providers: [
    TableService,
    {
      provide: Table,
      useFactory: tableFactory,
      deps: [TableComponent]
    }
  ]
})
export class TableComponent {

  @Input()
  data: any[];

  @ContentChild('header', { static: false })
  public headerTemplate: TemplateRef<any>;
  
  @ContentChild('body', { static: false })
  public bodyTempate: TemplateRef<any>;

  @ViewChild('primengTable', { static: true }) public primengTable: Table;
}
<div class="my-table">
    <p-table #primengTable [value]="data">
      <ng-template pTemplate="header">
        <ng-container *ngTemplateOutlet="headerTemplate"></ng-container>
      </ng-template>
      <ng-template pTemplate="body" let-item let-rowIndex="rowIndex">
        <ng-container *ngTemplateOutlet="bodyTempate;context:{ $implicit: item, rowIndex: rowIndex }"></ng-container> 
      </ng-template>
    </p-table>
</div>

注意:primengTable 公开只是因为我想从外部访问它以进行复杂的操作。此代码仍然可以正常工作。

用法:

<my-table [data]="data">
    <ng-template #header>
        <tr>
            <th>Index</th>
            <th pSortableColumn="name">Name <p-sortIcon field="name"></p-sortIcon></th>
            <th pSortableColumn="age">Age <p-sortIcon field="age"></p-sortIcon></th>
        </tr>
    </ng-template>
    <ng-template #body let-item let-rowIndex="rowIndex">
        <tr>
            <td>{{ rowIndex }}</td>
            <td>{{ item.name }}</td>
            <td>{{ item.age }}</td>
        </tr>
    </ng-template>
</my-table>
相关问题