Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(core): data table custom value templates and header formatter #234

Merged
merged 1 commit into from
Feb 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 15 additions & 2 deletions libs/shared/src/features/data-table/data-table.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,23 @@
<table mat-table matSort [dataSource]="dataSource" [matSortDisabled]="!tableOptions.sort">
@for(column of tableOptions.displayColumns; track column){
<ng-container [matColumnDef]="column">
<th mat-header-cell *matHeaderCellDef mat-sort-header>{{ column }}</th>
<td mat-cell *matCellDef="let el">{{ el[column] }}</td>
<th mat-header-cell *matHeaderCellDef mat-sort-header>{{ column | formatValue: tableOptions.formatHeader }}</th>

<td mat-cell *matCellDef="let el">
@if(valueTemplates[column]){
<!-- custom value templates -->
<ng-container
[ngTemplateOutlet]="valueTemplates[column]"
[ngTemplateOutletContext]="{ $implicit: el[column] }"
></ng-container>
} @else {
<!-- Default value template -->
{{ el[column] }}
}
</td>
</ng-container>
}

<tr mat-header-row *matHeaderRowDef="tableOptions.displayColumns"></tr>
<tr
mat-row
Expand Down
61 changes: 58 additions & 3 deletions libs/shared/src/features/data-table/data-table.component.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,23 @@
import { CommonModule } from '@angular/common';
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnChanges, ViewChild } from '@angular/core';
import {
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
Input,
OnChanges,
Pipe,
PipeTransform,
TemplateRef,
ViewChild,
} from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatIconModule } from '@angular/material/icon';
import { MatInputModule } from '@angular/material/input';
import { MatPaginator } from '@angular/material/paginator';
import { MatSort, MatSortModule } from '@angular/material/sort';
import { MatTableDataSource, MatTableModule } from '@angular/material/table';
import { capitalise } from '@picsa/utils';
import download from 'downloadjs';
import { unparse } from 'papaparse';

Expand All @@ -21,15 +32,50 @@
search?: boolean;
/** Specify whether to include column sort headers (default true) */
sort?: boolean;
/** Apply custom formatter to header values. Default replaces underscore with space and capitalises each word */
formatHeader?: (value: string) => string;
/** Bind to row click events */
handleRowClick?: (row: any) => void;

Check warning on line 38 in libs/shared/src/features/data-table/data-table.component.ts

View workflow job for this annotation

GitHub Actions / build

Unexpected any. Specify a different type
}

/**
* Simple pipe that allows providing a custom formatter function,
* used to modify cell values in a pure way
*/
@Pipe({
standalone: true,
name: 'formatValue',
})
export class FormatValuePipe implements PipeTransform {
transform<T, U = T>(value: T, formatter: (v: T) => U) {
if (!formatter) return value;
return formatter(value);
}
}

/**
* The `picsa-data-table` component is a lightweight wrapper around `mat-table`, used
* to simplify display of basic tables.
*
* By default the table has support for sort, pagination and data search (filter)
* @example
* ```
* <picsa-data-table [data]="myData"></picsa-data-table>
* ```
* The table has support for sort, pagination and data search (filter),
* enabled by default and configurable by an options input @see IDataTableOptions
* @example
* ```
* <picsa-data-table [data]="myData" [options]="{search:false}"></picsa-data-table>
* ```
* The table will display all cell values directly, without any additional formatting
* If needing to render values within a custom template this can be done via `valueTemplates`
* @example
* ```
* <picsa-data-table [data]="myData" [valueTemplates]={col1:col1Template}>
* <ng-template #col1Template let-value>
* <span class='some-custom-class'>{{value | modifierPipe}}</span>
* </ng-template>
* </picsa-data-table>
* ```
*
* For more advanced use cases such as custom column display prefer to directly use `mat-table`
*/
Expand All @@ -38,6 +84,7 @@
standalone: true,
imports: [
CommonModule,
FormatValuePipe,
MatButtonModule,
MatFormFieldModule,
MatIconModule,
Expand All @@ -51,11 +98,18 @@
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class PicsaDataTableComponent implements OnChanges {
@Input() data: Record<string, any>[] = [];

Check warning on line 101 in libs/shared/src/features/data-table/data-table.component.ts

View workflow job for this annotation

GitHub Actions / build

Unexpected any. Specify a different type

/** User option overrides */
@Input() options: IDataTableOptions = {};

/**
* Optional <ng-template> references to display specific column values in a custom template,
* indexed by column name. E.g. `{colA: myCustomTemplate}`
* https://angular.io/guide/content-projection#conditional-content-projection
*/
@Input() valueTemplates: Record<string, TemplateRef<{ $implicit: any }>> = {};

Check warning on line 111 in libs/shared/src/features/data-table/data-table.component.ts

View workflow job for this annotation

GitHub Actions / build

Unexpected any. Specify a different type

@ViewChild(MatPaginator) paginator: MatPaginator;
@ViewChild(MatSort) sort: MatSort;

Expand All @@ -66,9 +120,10 @@
search: true,
sort: true,
handleRowClick: () => null,
formatHeader: (v) => v.split('_').map(capitalise).join(' '),
};

public dataSource: MatTableDataSource<any>;

Check warning on line 126 in libs/shared/src/features/data-table/data-table.component.ts

View workflow job for this annotation

GitHub Actions / build

Unexpected any. Specify a different type

constructor(private cdr: ChangeDetectorRef) {}

Expand Down
6 changes: 6 additions & 0 deletions libs/utils/data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,3 +84,9 @@ export function jsonNestedProperty<T>(obj: any, nestedPath: string) {
export function base64ToBlob(base64String, mimetype: string) {
return createBlobFromBase64(base64String, mimetype);
}

/** Capitalise the first letter of a string */
export function capitalise(str: string) {
if (typeof str !== 'string') return str;
return str.charAt(0).toUpperCase() + str.slice(1);
}
Loading