Primeng: DataTable: dynamic p-column with ngFor and cell template

Created on 13 Oct 2016  路  6Comments  路  Source: primefaces/primeng

We are trying to use a <p-column *ngFor="let col of cols" ... to display a dynamic number of columns, and also trying to use a <template pTemplate ... to specify how a cell is being rendered.

We try to do it this way:

    <p-column *ngFor="let col of cols" [field]="col.field" [header]="col.header | translate" [sortable]="true">
        <template let-row="rowData" pTemplate>
            <span>{{row[col.field] | mypipe}}</span>
        </template>
    </p-column>

This results in only a single row being rendered which only has the first column/cell written.
Is there any working way to get a dynamic number of columns with rendering a cell using an Angular 2 pipe?

Environment:

  • Angular version: 2.1.0
  • Typescript version: 2.0.3
  • PrimeNG version: 1.0.0-beta.17

Most helpful comment

@dereklin Sure. The easiest solution in this case was just implementing a custom Angular 2 Pipe which does the dot-into interpretation with a pipe argument being the selector string.
This is the relevant portion of the template we are currently using:

    <p-column ...>
        <template let-row="rowData" pTemplate type="body">
            <span>{{row | extractProperty:col.field}}</span>
        </template>
    </p-column>

You see here we are simply using a custom Angular 2 Pipe called "extractProperty" (in hindsight this could have probably named better).
The definition of the quickly prototyped pipe is as follows:

import { Pipe, PipeTransform } from '@angular/core';
@Pipe({name: 'extractProperty'})
export class ExtractPropertyPipe implements PipeTransform {
    transform(value: any, selector: string): string {
        if (!selector) {
            throw new Error('missing selector');
        }
        let dot = selector.indexOf('.');
        let context = value;
        let rest = selector;
        while (dot > 0) {
            if (!context) {
                throw new Error('no object defined from which a property could be extracted');
            }
            let beforeDot = rest.substr(0, dot);
            context = context[beforeDot];
            rest = rest.substr(dot + 1);
            dot = rest.indexOf('.');
        }
        if (!context) {
            throw new Error('no object defined from which a property could be extracted');
        }
        return context[rest];
    }
}

I take no responsibility for any crashes/malfunctioning that are due to bugs in that code. :)

All 6 comments

Sorry, was a mistake at our side. Everything is working exactly like it should. The problem was that col.field was a string that contained _dots_ for selecting sub-properties. This was supported inherently by the datatable, but had to be programmed manually when using a normal JavaScript property lookup in the template via Angular's handlebars.

@dereklin Sure. The easiest solution in this case was just implementing a custom Angular 2 Pipe which does the dot-into interpretation with a pipe argument being the selector string.
This is the relevant portion of the template we are currently using:

    <p-column ...>
        <template let-row="rowData" pTemplate type="body">
            <span>{{row | extractProperty:col.field}}</span>
        </template>
    </p-column>

You see here we are simply using a custom Angular 2 Pipe called "extractProperty" (in hindsight this could have probably named better).
The definition of the quickly prototyped pipe is as follows:

import { Pipe, PipeTransform } from '@angular/core';
@Pipe({name: 'extractProperty'})
export class ExtractPropertyPipe implements PipeTransform {
    transform(value: any, selector: string): string {
        if (!selector) {
            throw new Error('missing selector');
        }
        let dot = selector.indexOf('.');
        let context = value;
        let rest = selector;
        while (dot > 0) {
            if (!context) {
                throw new Error('no object defined from which a property could be extracted');
            }
            let beforeDot = rest.substr(0, dot);
            context = context[beforeDot];
            rest = rest.substr(dot + 1);
            dot = rest.indexOf('.');
        }
        if (!context) {
            throw new Error('no object defined from which a property could be extracted');
        }
        return context[rest];
    }
}

I take no responsibility for any crashes/malfunctioning that are due to bugs in that code. :)

@httpdigest Thanks for your example! You responded so quickly. I removed my question because I got what you said in your original post and implemented a simple function for displaying the value:

  public displayData(store, key) {
    let myKeys = key.split('.');
    let value: any = store;
    myKeys.forEach((k) => {
      value = value[k];
    });
    return value;
  }

@httpdigest Hi, I got the requirement to generate columns dynamically, could you please guide me how to do that?

Hi @XtheWiz , did you get it done ?

@rana3012 Yes, but I have another problem right now :(

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Faigjaz picture Faigjaz  路  3Comments

Helayxa picture Helayxa  路  3Comments

Helayxa picture Helayxa  路  3Comments

gatapia picture gatapia  路  3Comments

philly-vanilly picture philly-vanilly  路  3Comments