I'm submitting a ... (check one with "x")
[ ] bug report => search github for a similar issue or PR before submitting
[X] feature request
[ ] support request => Please do not submit support request here
Current behavior
Data must be formatted before being introduced to the table
Expected behavior
It would be helpful if we were able to pass in a format string / function to a column for formatting purposes.
What is the motivation / use case for changing the behavior?
I have a lot of columns that have dates stored in ISO 8601 format (which is great for data, but not so much for humans), and it would be great if the table could format the data as it's rendering.
Table version: 0.7.x
4.1.0
Angular version: 2.0.x
2.4.1
Language: [all | TypeScript X.X | ES6/7 | ES5]
Typescript
Already implemented, pass pipe on your column def.... https://github.com/swimlane/ngx-datatable/blob/master/src/components/body/body-cell.component.ts#L88
@amcdnl Ok, thank you, didn't see this in the documentation or in the Demos.
Mind doing a PR to add to the docs?
Do you have a quick example on how I would go about passing a pipe to a column def?
I've solved this by adding a type to the column def then using a *ngSwitch in the template and then piping the value to date.
Would you mind updating the documentation or providing an example of how this would work? I am using version 6.3.0.
Nevermind, please ignore comment. Found it:
<ngx-datatable-column name="plannedStartDate">
<template let-column="column" ngx-datatable-header-template>
<span jhiTranslate="app.project.plannedStartDate">Planned Start</span>
</template>
<template let-value="value" ngx-datatable-cell-template>
{{value | date: 'MM/dd/yyyy'}}
</template>
</ngx-datatable-column>
@kiranaddepalli
I'm also looking for a solution to this problem. Please could you expand your solution and show where you place the <ngx-datatable-column name="myColumn"> tag in your table template.
@SauceCode84 No magic in the rest of the stuff. Its the standard ngx-datatable template but here you go:
Three things in this code below:
<ngx-datatable class="material striped"
[rows]="addresses"
[columnMode]="'force'"
[headerHeight]="50"
[footerHeight]="0"
[rowHeight]="50"
[scrollbarV]="true"
[scrollbarH]="true">
<ngx-datatable-column prop="createdDate" [width]="120">
<ng-template let-column="column" ngx-datatable-header-template>
Since
</ng-template>
<ng-template let-value="value" ngx-datatable-cell-template>
{{value | date: 'MM/dd/yyyy'}}
</ng-template>
</ngx-datatable-column>
<!-- Rest of the columns -->
<ngx-datatable-column>
<ng-template let-column="column" ngx-datatable-header-template>
Location
</ng-template>
<ng-template let-row="row" ngx-datatable-cell-template>
{{row.addressLine1}} {{row.city}},{{row.state}} {{row.zipcode}}
</ng-template>
</ngx-datatable-column>
</ngx-datatable>
Hope this helps.
@kiranaddepalli
Thanks for the feedback! I managed to get something going on my side as well.
The real issue with this is that you have to now create templates for all the columns in this fashion in order to apply a template to just one column. This seems counter intuitive... or I'm clearly missing something.
Will let the original developers comment on the best approach. My UI skills are limited. So far it has been fantastic in my applications.
@SauceCode84 - Can I think we should support this in the core. I believe we support pipes for cells, just need to apply this to column headers too.
@amcdnl
Would you mind giving an example? Both cells and headers.
@amcdnl If I use let-column in ng-template then pipes work fine, but it breaks sorting. If I use name in ngx-datatable-column then sorting works but pipes don't, which means I can't have localized column headers with working sorting. I want to do something like <ngx-datatable-column name="{{ 'NAME' | translate }}" prop="name">
I've just come across this use case as well - so is it right that there's no way to apply a pipe to a single column without also having to define templates manually for all the other columns (which are fine by default)? Just checking I'm not missing something....
I guess ideally what I'd want is to be able apply the pipe where the column is defined in the typescript file - if I do this at the moment it throws an error:
userPipe.transform is not a function at DataTableBodyCellComponent.get
@mattf80 I've solved the problem with the following workaround. I inject the table into my component with
@ViewChild(DatatableComponent) table: DatatableComponent; then I can modify column names like this.table.columns[idx].name = value. My full code is something like this:
this.translate.onLangChange.subscribe((event: LangChangeEvent) => this.translateColumns());
...
private translateColumns() {
this.columns.map((value, idx) => {
this.translate.get(value).subscribe(translated=> {
this.table.columns[idx+1].name = translated; // +1, because first column is for the checkboxes
});
});
}
...
ngAfterViewInit() {
this.translateColumns();
}
@adamszeibert thanks for this! It has set me on the right track, I think I can get it working now.
@amcdnl how do we use pipe in columns json definition? Even if I use DatePipe I get userPipe.transform is not a function.
columns = [{
name: 'Date',
prop: 'dateReported',
pipe: DatePipe
}];
Edit: I figured this out. I need to pass an instance of the userPipe. Now, how do I pass parameters to this pipe? Any thoughts?
@ganeshkantu, you could do something like this:
class DateOnlyPipe extends DatePipe {
public transform(value): any {
return super.transform(value, 'MM/dd/y');
}
}
const columns = [{
name: 'Date',
prop: 'dateReported',
pipe: new DateOnlyPipe('en-US')
}];
@ganeshkantu I used a little bit of lodash
constructor(
...,
private router: Router,
private CURRENCY: CurrencyPipe
) {
// USDs with $
const pipe_$ = {transform: _.partial(CURRENCY.transform, _, 'USD', true)};
this.columns = [
{ name: 'Name', flexGrow: 1},
{ name: 'Payment', prop: 'payment', pipe: pipe_$, flexGrow: 1}
];
}
@maburdi94 , I have a custom pipe that I am using to format data in my table. In that pipe, I would like to be able to have access to the data in the row so that I could dynamically use a different format for certain rows. For example, I have a table where I have four rows, two of which are just the same data as the other two, except I want to display it in both dollar values and percentages. Like this:
col1 col2 col3
$1 $2 $2
20% 40% 40%
When I was using a different table package that had a valuePrepareFunction() on the column definitions, I would simply look at a field I called formatType to see if I should format using a PercentPipe or a CurrencyPipe. I can't do that here (or I can't figure out how to)
Any suggestions would be appreciated.
I have tried using pipe for date format but it didn't work for me.
Can anyone have an idea or how we can resolve this?
CODE:
<ngx-datatable-column prop="RequestSubmittedDateTime" name="RequestSubmittedDateTime" [width]="150" [draggable]="false" [sortable]="true" >
<ng-template let-column="column" let-sort="sortFn" ngx-datatable-header-template>
<div class="dt-header"></div>
<div class="dk-blue-text m-q" (click)="sort()">
<strong class="adminPanelHeaderTxt">Request Date</strong></div>
</ng-template>
<ng-template let-value="value" ngx-datatable-cell-template>
{{value | date:'M/d/yy h:mm a'}}
</ng-template>
</ngx-datatable-column>
my HTML:
[rowHeight]="'auto'"
[scrollbarH]="true"
class="bootstrap"
[columnMode]="'force'"
[reorderable]="'false'"
[headerHeight]="50"
[footerHeight]="50"
[limit]="ITEM_PER_PAGE"
[hidden]="rows.length === 0"
#table
>
*ngFor="let col of columns;"
[prop]="col.prop"
[cellTemplate]="col.cellTemplate"
[maxWidth]="col.maxWidth"
>
.ts code:
private getStatusSummary(clearCache?: boolean) {
this.loaderService.startLoader(this.loader.id);
let params = {
reportname: 'getscriptstatusdisplay',
fromDate: '',
toDate: ''
};
params = merge({}, params, this.filters);
this.httpClient
.cache(clearCache)
.get(`/${API.NAME}`, {
params: params
})
.subscribe(
(data: any) => {
this.loaderService.stopLoader(this.loader.id);
const error = get(data, 'errorMessage', '');
const records = get(data, 'body', []);
if (error) {
} else
{
this.rows = records;
let _cols =
isArray(this.rows) && this.rows.length > 0
? Object.keys(get(this.rows, '[0]')).map((i, index) => {
return {
prop: i,
index: index
};
})
: [];
this.tempRows = records;
this.columns = _cols;
this.allColumns = _cols;
this.columns.push({
prop: 'Action',
index: this.columns.length,
width: 100,
resizeable: false,
sortable: false,
cellTemplate: this.actionTemplate
});
this.setError('');
}
},
error => {
this.loaderService.stopLoader(this.loader.id);
this.setError(error);
}
);
}
how i can apply pipe for specific field..? any idea..?
@Ragasrm you need to add pipe property to the columns you want to add it to. Like this:
...
this.columns.push({
prop: 'Action',
index: this.columns.length,
width: 100,
resizeable: false,
sortable: false,
cellTemplate: this.actionTemplate,
pipe: new yourPipe(), // pass an instance of the pipe you want to use as a property of the column
});
Hope that helps.
Most helpful comment
@ganeshkantu, you could do something like this: